This commit is contained in:
Mikaël Cluseau
2018-06-17 18:32:44 +11:00
parent f92c531f5d
commit 4d889632f6
500 changed files with 133832 additions and 0 deletions

94
vendor/github.com/cloudflare/cfssl/auth/auth.go generated vendored Normal file
View File

@ -0,0 +1,94 @@
// Package auth implements an interface for providing CFSSL
// authentication. This is meant to authenticate a client CFSSL to a
// remote CFSSL in order to prevent unauthorised use of the signature
// capabilities. This package provides both the interface and a
// standard HMAC-based implementation.
package auth
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"io/ioutil"
"os"
"strings"
)
// An AuthenticatedRequest contains a request and authentication
// token. The Provider may determine whether to validate the timestamp
// and remote address.
type AuthenticatedRequest struct {
// An Authenticator decides whether to use this field.
Timestamp int64 `json:"timestamp,omitempty"`
RemoteAddress []byte `json:"remote_address,omitempty"`
Token []byte `json:"token"`
Request []byte `json:"request"`
}
// A Provider can generate tokens from a request and verify a
// request. The handling of additional authentication data (such as
// the IP address) is handled by the concrete type, as is any
// serialisation and state-keeping.
type Provider interface {
Token(req []byte) (token []byte, err error)
Verify(aReq *AuthenticatedRequest) bool
}
// Standard implements an HMAC-SHA-256 authentication provider. It may
// be supplied additional data at creation time that will be used as
// request || additional-data with the HMAC.
type Standard struct {
key []byte
ad []byte
}
// New generates a new standard authentication provider from the key
// and additional data. The additional data will be used when
// generating a new token.
func New(key string, ad []byte) (*Standard, error) {
if splitKey := strings.SplitN(key, ":", 2); len(splitKey) == 2 {
switch splitKey[0] {
case "env":
key = os.Getenv(splitKey[1])
case "file":
data, err := ioutil.ReadFile(splitKey[1])
if err != nil {
return nil, err
}
key = string(data)
default:
return nil, fmt.Errorf("unknown key prefix: %s", splitKey[0])
}
}
keyBytes, err := hex.DecodeString(key)
if err != nil {
return nil, err
}
return &Standard{keyBytes, ad}, nil
}
// Token generates a new authentication token from the request.
func (p Standard) Token(req []byte) (token []byte, err error) {
h := hmac.New(sha256.New, p.key)
h.Write(req)
h.Write(p.ad)
return h.Sum(nil), nil
}
// Verify determines whether an authenticated request is valid.
func (p Standard) Verify(ad *AuthenticatedRequest) bool {
if ad == nil {
return false
}
// Standard token generation returns no error.
token, _ := p.Token(ad.Request)
if len(ad.Token) != len(token) {
return false
}
return hmac.Equal(token, ad.Token)
}

159
vendor/github.com/cloudflare/cfssl/auth/auth_test.go generated vendored Normal file
View File

@ -0,0 +1,159 @@
package auth
import (
"encoding/json"
"io/ioutil"
"testing"
)
var (
testProvider Provider
testProviderAD Provider
testKey = "0123456789ABCDEF0123456789ABCDEF"
testAD = []byte{1, 2, 3, 4} // IP address 1.2.3.4
)
func TestNew(t *testing.T) {
_, err := New("ABC", nil)
if err == nil {
t.Fatal("expected failure with improperly-hex-encoded key")
}
testProvider, err = New(testKey, nil)
if err != nil {
t.Fatalf("%v", err)
}
testProviderAD, err = New(testKey, testAD)
if err != nil {
t.Fatalf("%v", err)
}
}
var (
testRequest1A = &AuthenticatedRequest{
Request: []byte(`testing 1 2 3`),
}
testRequest1B = &AuthenticatedRequest{
Request: []byte(`testing 1 2 3`),
}
testRequest2 = &AuthenticatedRequest{
Request: []byte(`testing 3 2 1`),
}
)
// Sanity check: can a newly-generated token be verified?
func TestVerifyTrue(t *testing.T) {
var err error
testRequest1A.Token, err = testProvider.Token(testRequest1A.Request)
if err != nil {
t.Fatalf("%v", err)
}
testRequest1B.Token, err = testProviderAD.Token(testRequest1B.Request)
if err != nil {
t.Fatalf("%v", err)
}
if !testProvider.Verify(testRequest1A) {
t.Fatal("failed to verify request 1A")
}
if !testProviderAD.Verify(testRequest1B) {
t.Fatal("failed to verify request 1B")
}
}
// Sanity check: ensure that additional data is actually used in
// verification.
func TestVerifyAD(t *testing.T) {
if testProvider.Verify(testRequest1B) {
t.Fatal("no-AD provider verifies request with AD")
}
if testProviderAD.Verify(testRequest1A) {
t.Fatal("AD provider verifies request without AD")
}
}
// Sanity check: verification fails if tokens are not the same length.
func TestTokenLength(t *testing.T) {
token := testRequest1A.Token[:]
testRequest1A.Token = testRequest1A.Token[1:]
if testProvider.Verify(testRequest1A) {
t.Fatal("invalid token should not be verified")
}
testRequest1A.Token = token
}
// Sanity check: token fails validation if the request is changed.
func TestBadRequest(t *testing.T) {
testRequest2.Token = testRequest1A.Token
if testProvider.Verify(testRequest2) {
t.Fatal("bad request should fail verification")
}
}
// Sanity check: a null request should fail to verify.
func TestNullRequest(t *testing.T) {
if testProvider.Verify(nil) {
t.Fatal("null request should fail verification")
}
}
// Sanity check: verify a pre-generated authenticated request.
func TestPreGenerated(t *testing.T) {
in, err := ioutil.ReadFile("testdata/authrequest.json")
if err != nil {
t.Fatalf("%v", err)
}
var req AuthenticatedRequest
err = json.Unmarshal(in, &req)
if err != nil {
t.Fatalf("%v", err)
}
if !testProvider.Verify(&req) {
t.Fatal("failed to verify pre-generated request")
}
}
var bmRequest []byte
func TestLoadBenchmarkRequest(t *testing.T) {
in, err := ioutil.ReadFile("testdata/request.json")
if err != nil {
t.Fatalf("%v", err)
}
bmRequest = in
}
func BenchmarkToken(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := testProvider.Token(bmRequest)
if err != nil {
b.Fatalf("%v", err)
}
}
}
func BenchmarkVerify(b *testing.B) {
token, _ := testProvider.Token(bmRequest)
req := &AuthenticatedRequest{
Token: token,
Request: bmRequest,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if !testProvider.Verify(req) {
b.Fatal("failed to verify request")
}
}
}

View File

@ -0,0 +1 @@
{"token": "tSU1WTE/322iXrOBfJSQ9/u1dleqpwUmCj1LXYHw07Y=", "request": "ewoJImhvc3RuYW1lIjogImt5bGVpc29tLm5ldCIsCgkicmVxdWVzdCI6ICItLS0tLUJFR0lOIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQoJICAgIE1JSUQwVENDQWpzQ0FRQXdZREVMTUFrR0ExVUVCaE1DVlZNeEVqQVFCZ05WQkFvVENXUnliM0J6YjI1a1pURVEKCSAgICBNQTRHQTFVRUN4TUhRMFl0UTJoaGRERVdNQlFHQTFVRUJ4TU5VMkZ1SUVaeVlXNWphWE5qYnpFVE1CRUdBMVVFCgkgICAgQ0JNS1EyRnNhV1p2Y201cFlUQ0NBYUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0dQQURDQ0FZb0NnZ0dCQU1jQwoJICAgIEdCbDVMVHJla0dGV2hvdGtkYlorUjFNbG9hcld4UXY5alA0QWVrdDhVT2ljeXBIdkZPNnhPdFN3SG8rcjMyaUUKCSAgICBxblM1eXYvMDFQMk1KdXlxbmRuY1RTTXNPbFQvN242N1RNMDB1MDFLLzljL3NvZ0tFS2pseXBsVFA3eUZkRy9jCgkgICAgT3UvOXFLYi9KYWxkMndFTEZZRTZ4cTJSREZ5eHlpWk9CM2c3WjdGeGE1ZDZhZGZHUndaek50VUw0LzhzK0x5aQoJICAgIHFkdzlJMWZrUWQ2MDRwb1pGTjB3clFzNGxmaFdUVWZnMHJIdWg1d2dHS1AzVnpacGJ0OEZiMXZOamZiSHRvaHgKCSAgICBHMlBDVTZKeStEYzFiU2ZVeldjUW5lbnA4NThXNEY4ejdwRjV5YmRuRlIzMTNIam9zcVhuRzI4eklUck9hZE1UCgkgICAgSGFKNnpPaGdFYWZVT1dYT3pqTm9mRkJGYTJJdUNBVCtJVFJZMXRDL2dxcHhHd0gveXVWTjE5Qkc4VXBuMCtIQQoJICAgIGllMm1LQ0hmU0JBS1QvWGU0dW1QZWF4U2JJcVdzVzhjaytkM2I0b3I5Ulp2NWNaUmNUM29pa0p0K1NRRzY5cFcKCSAgICA0T0FiYitBQnNzL05JdXJpNnowZTdERWVJTDV6bXlTSnFkdFlIZE5ZTjcrK3Y5eEJOc0w0SXNVNklFeTMrUUlECgkgICAgQVFBQm9DNHdMQVlKS29aSWh2Y05BUWtPTVI4d0hUQWJCZ05WSFJFRUZEQVNnaEJqWmk1a2NtOXdjMjl1WkdVdQoJICAgIGJtVjBNQXNHQ1NxR1NJYjNEUUVCREFPQ0FZRUFoTUFxQmlySStrMWFVM2xmQUdRaVNtOHl0T3paaWozODloSXIKCSAgICBuVXA4K1duVHVWVGI4WFozL1YrTDlFblRJbUY2dTF3ZWFqWGQzU3VlNDk1NzBMYlltSXV4QmtHcDUwL0JkVUR6CgkgICAgdUI2eHNoaEpXczEySnhVYjkxSW1tMGJUUncyek1xZXdnYTZmdHpaL0FLNG1zeFFBMlVJYmNXWmRzS2J1TTdzbwoJICAgIEpUZlZXOWlPd3FIdC82NFpqNHRCWmY5THpPRHI3a051S0tMbndqaXpIMTg3eGZJSWhkcmpGOFdTN0g5QVBCMU8KCSAgICBTdUVVRGZxaDBTV1IzbHRXdUF1VVdlbzZTS2NIVnVzeS9HNFlFK1BCeXcxZVY3RzRTYmVHNVowbytHT1VVSy9GCgkgICAgYjU1R21XMXhhNExBcnMxQSt6ZUZidkovQkFwc2JVMmI2V1ZtTmE3V3BIejdXWElGT0p1WUpnRWtWS1BKbkt1cwoJICAgIHFxczNGZ1VxejBadjdUSzhtTWlFVEpvWFpzNnpDdk15c1FldTNKL29qZ3RBanZNaHpRYzZQUy9udk90SmRJZysKCSAgICBIMHFYNDlmaHAxQnJZeXNsYWx6UUlGMCtIMHFTVWV5b1V5VjJ3YkxCQUxhcHhNZnZUVmxoTnduYWN0Y0tReHE0CgkgICAgK3dUKzJQVEowYk0vNUFWMFRPMVNQVDBBVmlKaAoJICAgIC0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLSIsCgkicHJvZmlsZSI6ICIiLAoJInJlbW90ZSI6ICIiLAoJImxhYmVsIjogInByaW1hcnkiCn0KCg=="}

View File

@ -0,0 +1,30 @@
{
"hostname": "kyleisom.net",
"request": "-----BEGIN CERTIFICATE REQUEST-----
MIID0TCCAjsCAQAwYDELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCWRyb3Bzb25kZTEQ
MA4GA1UECxMHQ0YtQ2hhdDEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UE
CBMKQ2FsaWZvcm5pYTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAMcC
GBl5LTrekGFWhotkdbZ+R1MloarWxQv9jP4Aekt8UOicypHvFO6xOtSwHo+r32iE
qnS5yv/01P2MJuyqndncTSMsOlT/7n67TM00u01K/9c/sogKEKjlyplTP7yFdG/c
Ou/9qKb/Jald2wELFYE6xq2RDFyxyiZOB3g7Z7Fxa5d6adfGRwZzNtUL4/8s+Lyi
qdw9I1fkQd604poZFN0wrQs4lfhWTUfg0rHuh5wgGKP3VzZpbt8Fb1vNjfbHtohx
G2PCU6Jy+Dc1bSfUzWcQnenp858W4F8z7pF5ybdnFR313HjosqXnG28zITrOadMT
HaJ6zOhgEafUOWXOzjNofFBFa2IuCAT+ITRY1tC/gqpxGwH/yuVN19BG8Upn0+HA
ie2mKCHfSBAKT/Xe4umPeaxSbIqWsW8ck+d3b4or9RZv5cZRcT3oikJt+SQG69pW
4OAbb+ABss/NIuri6z0e7DEeIL5zmySJqdtYHdNYN7++v9xBNsL4IsU6IEy3+QID
AQABoC4wLAYJKoZIhvcNAQkOMR8wHTAbBgNVHREEFDASghBjZi5kcm9wc29uZGUu
bmV0MAsGCSqGSIb3DQEBDAOCAYEAhMAqBirI+k1aU3lfAGQiSm8ytOzZij389hIr
nUp8+WnTuVTb8XZ3/V+L9EnTImF6u1weajXd3Sue49570LbYmIuxBkGp50/BdUDz
uB6xshhJWs12JxUb91Imm0bTRw2zMqewga6ftzZ/AK4msxQA2UIbcWZdsKbuM7so
JTfVW9iOwqHt/64Zj4tBZf9LzODr7kNuKKLnwjizH187xfIIhdrjF8WS7H9APB1O
SuEUDfqh0SWR3ltWuAuUWeo6SKcHVusy/G4YE+PByw1eV7G4SbeG5Z0o+GOUUK/F
b55GmW1xa4LArs1A+zeFbvJ/BApsbU2b6WVmNa7WpHz7WXIFOJuYJgEkVKPJnKus
qqs3FgUqz0Zv7TK8mMiETJoXZs6zCvMysQeu3J/ojgtAjvMhzQc6PS/nvOtJdIg+
H0qX49fhp1BrYyslalzQIF0+H0qSUeyoUyV2wbLBALapxMfvTVlhNwnactcKQxq4
+wT+2PTJ0bM/5AV0TO1SPT0AViJh
-----END CERTIFICATE REQUEST-----",
"profile": "",
"remote": "",
"label": "primary"
}

75
vendor/github.com/cloudflare/cfssl/certdb/README.md generated vendored Normal file
View File

@ -0,0 +1,75 @@
# certdb usage
Using a database enables additional functionality for existing commands when a
db config is provided:
- `sign` and `gencert` add a certificate to the certdb after signing it
- `serve` enables database functionality for the sign and revoke endpoints
A database is required for the following:
- `revoke` marks certificates revoked in the database with an optional reason
- `ocsprefresh` refreshes the table of cached OCSP responses
- `ocspdump` outputs cached OCSP responses in a concatenated base64-encoded format
## Setup/Migration
This directory stores [goose](https://bitbucket.org/liamstask/goose/) db migration scripts for various DB backends.
Currently supported:
- MySQL in mysql
- PostgreSQL in pg
- SQLite in sqlite
### Get goose
go get bitbucket.org/liamstask/goose/cmd/goose
### Use goose to start and terminate a MySQL DB
To start a MySQL using goose:
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql up
To tear down a MySQL DB using goose
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql down
Note: the administration of MySQL DB is not included. We assume
the databases being connected to are already created and access control
is properly handled.
### Use goose to start and terminate a PostgreSQL DB
To start a PostgreSQL using goose:
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/pg up
To tear down a PostgreSQL DB using goose
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/pg down
Note: the administration of PostgreSQL DB is not included. We assume
the databases being connected to are already created and access control
is properly handled.
### Use goose to start and terminate a SQLite DB
To start a SQLite DB using goose:
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up
To tear down a SQLite DB using goose
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down
## CFSSL Configuration
Several cfssl commands take a -db-config flag. Create a file with a
JSON dictionary:
{"driver":"sqlite3","data_source":"certs.db"}
or
{"driver":"postgres","data_source":"postgres://user:password@host/db"}
or
{"driver":"mysql","data_source":"user:password@tcp(hostname:3306)/db?parseTime=true"}

42
vendor/github.com/cloudflare/cfssl/certdb/certdb.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
package certdb
import (
"time"
)
// CertificateRecord encodes a certificate and its metadata
// that will be recorded in a database.
type CertificateRecord struct {
Serial string `db:"serial_number"`
AKI string `db:"authority_key_identifier"`
CALabel string `db:"ca_label"`
Status string `db:"status"`
Reason int `db:"reason"`
Expiry time.Time `db:"expiry"`
RevokedAt time.Time `db:"revoked_at"`
PEM string `db:"pem"`
}
// OCSPRecord encodes a OCSP response body and its metadata
// that will be recorded in a database.
type OCSPRecord struct {
Serial string `db:"serial_number"`
AKI string `db:"authority_key_identifier"`
Body string `db:"body"`
Expiry time.Time `db:"expiry"`
}
// Accessor abstracts the CRUD of certdb objects from a DB.
type Accessor interface {
InsertCertificate(cr CertificateRecord) error
GetCertificate(serial, aki string) ([]CertificateRecord, error)
GetUnexpiredCertificates() ([]CertificateRecord, error)
GetRevokedAndUnexpiredCertificates() ([]CertificateRecord, error)
GetRevokedAndUnexpiredCertificatesByLabel(label string) ([]CertificateRecord, error)
RevokeCertificate(serial, aki string, reasonCode int) error
InsertOCSP(rr OCSPRecord) error
GetOCSP(serial, aki string) ([]OCSPRecord, error)
GetUnexpiredOCSPs() ([]OCSPRecord, error)
UpdateOCSP(serial, aki, body string, expiry time.Time) error
UpsertOCSP(serial, aki, body string, expiry time.Time) error
}

659
vendor/github.com/cloudflare/cfssl/config/config.go generated vendored Normal file
View File

@ -0,0 +1,659 @@
// Package config contains the configuration logic for CFSSL.
package config
import (
"crypto/tls"
"crypto/x509"
"encoding/asn1"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"regexp"
"strconv"
"strings"
"time"
"github.com/cloudflare/cfssl/auth"
cferr "github.com/cloudflare/cfssl/errors"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/log"
ocspConfig "github.com/cloudflare/cfssl/ocsp/config"
)
// A CSRWhitelist stores booleans for fields in the CSR. If a CSRWhitelist is
// not present in a SigningProfile, all of these fields may be copied from the
// CSR into the signed certificate. If a CSRWhitelist *is* present in a
// SigningProfile, only those fields with a `true` value in the CSRWhitelist may
// be copied from the CSR to the signed certificate. Note that some of these
// fields, like Subject, can be provided or partially provided through the API.
// Since API clients are expected to be trusted, but CSRs are not, fields
// provided through the API are not subject to whitelisting through this
// mechanism.
type CSRWhitelist struct {
Subject, PublicKeyAlgorithm, PublicKey, SignatureAlgorithm bool
DNSNames, IPAddresses, EmailAddresses bool
}
// OID is our own version of asn1's ObjectIdentifier, so we can define a custom
// JSON marshal / unmarshal.
type OID asn1.ObjectIdentifier
// CertificatePolicy represents the ASN.1 PolicyInformation structure from
// https://tools.ietf.org/html/rfc3280.html#page-106.
// Valid values of Type are "id-qt-unotice" and "id-qt-cps"
type CertificatePolicy struct {
ID OID
Qualifiers []CertificatePolicyQualifier
}
// CertificatePolicyQualifier represents a single qualifier from an ASN.1
// PolicyInformation structure.
type CertificatePolicyQualifier struct {
Type string
Value string
}
// AuthRemote is an authenticated remote signer.
type AuthRemote struct {
RemoteName string `json:"remote"`
AuthKeyName string `json:"auth_key"`
}
// CAConstraint specifies various CA constraints on the signed certificate.
// CAConstraint would verify against (and override) the CA
// extensions in the given CSR.
type CAConstraint struct {
IsCA bool `json:"is_ca"`
MaxPathLen int `json:"max_path_len"`
MaxPathLenZero bool `json:"max_path_len_zero"`
}
// A SigningProfile stores information that the CA needs to store
// signature policy.
type SigningProfile struct {
Usage []string `json:"usages"`
IssuerURL []string `json:"issuer_urls"`
OCSP string `json:"ocsp_url"`
CRL string `json:"crl_url"`
CAConstraint CAConstraint `json:"ca_constraint"`
OCSPNoCheck bool `json:"ocsp_no_check"`
ExpiryString string `json:"expiry"`
BackdateString string `json:"backdate"`
AuthKeyName string `json:"auth_key"`
RemoteName string `json:"remote"`
NotBefore time.Time `json:"not_before"`
NotAfter time.Time `json:"not_after"`
NameWhitelistString string `json:"name_whitelist"`
AuthRemote AuthRemote `json:"auth_remote"`
CTLogServers []string `json:"ct_log_servers"`
AllowedExtensions []OID `json:"allowed_extensions"`
CertStore string `json:"cert_store"`
Policies []CertificatePolicy
Expiry time.Duration
Backdate time.Duration
Provider auth.Provider
RemoteProvider auth.Provider
RemoteServer string
RemoteCAs *x509.CertPool
ClientCert *tls.Certificate
CSRWhitelist *CSRWhitelist
NameWhitelist *regexp.Regexp
ExtensionWhitelist map[string]bool
ClientProvidesSerialNumbers bool
}
// UnmarshalJSON unmarshals a JSON string into an OID.
func (oid *OID) UnmarshalJSON(data []byte) (err error) {
if data[0] != '"' || data[len(data)-1] != '"' {
return errors.New("OID JSON string not wrapped in quotes." + string(data))
}
data = data[1 : len(data)-1]
parsedOid, err := parseObjectIdentifier(string(data))
if err != nil {
return err
}
*oid = OID(parsedOid)
return
}
// MarshalJSON marshals an oid into a JSON string.
func (oid OID) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%v"`, asn1.ObjectIdentifier(oid))), nil
}
func parseObjectIdentifier(oidString string) (oid asn1.ObjectIdentifier, err error) {
validOID, err := regexp.MatchString("\\d(\\.\\d+)*", oidString)
if err != nil {
return
}
if !validOID {
err = errors.New("Invalid OID")
return
}
segments := strings.Split(oidString, ".")
oid = make(asn1.ObjectIdentifier, len(segments))
for i, intString := range segments {
oid[i], err = strconv.Atoi(intString)
if err != nil {
return
}
}
return
}
const timeFormat = "2006-01-02T15:04:05"
// populate is used to fill in the fields that are not in JSON
//
// First, the ExpiryString parameter is needed to parse
// expiration timestamps from JSON. The JSON decoder is not able to
// decode a string time duration to a time.Duration, so this is called
// when loading the configuration to properly parse and fill out the
// Expiry parameter.
// This function is also used to create references to the auth key
// and default remote for the profile.
// It returns true if ExpiryString is a valid representation of a
// time.Duration, and the AuthKeyString and RemoteName point to
// valid objects. It returns false otherwise.
func (p *SigningProfile) populate(cfg *Config) error {
if p == nil {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("can't parse nil profile"))
}
var err error
if p.RemoteName == "" && p.AuthRemote.RemoteName == "" {
log.Debugf("parse expiry in profile")
if p.ExpiryString == "" {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("empty expiry string"))
}
dur, err := time.ParseDuration(p.ExpiryString)
if err != nil {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
}
log.Debugf("expiry is valid")
p.Expiry = dur
if p.BackdateString != "" {
dur, err = time.ParseDuration(p.BackdateString)
if err != nil {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
}
p.Backdate = dur
}
if !p.NotBefore.IsZero() && !p.NotAfter.IsZero() && p.NotAfter.Before(p.NotBefore) {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
}
if len(p.Policies) > 0 {
for _, policy := range p.Policies {
for _, qualifier := range policy.Qualifiers {
if qualifier.Type != "" && qualifier.Type != "id-qt-unotice" && qualifier.Type != "id-qt-cps" {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("invalid policy qualifier type"))
}
}
}
}
} else if p.RemoteName != "" {
log.Debug("match remote in profile to remotes section")
if p.AuthRemote.RemoteName != "" {
log.Error("profile has both a remote and an auth remote specified")
return cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
}
if remote := cfg.Remotes[p.RemoteName]; remote != "" {
if err := p.updateRemote(remote); err != nil {
return err
}
} else {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("failed to find remote in remotes section"))
}
} else {
log.Debug("match auth remote in profile to remotes section")
if remote := cfg.Remotes[p.AuthRemote.RemoteName]; remote != "" {
if err := p.updateRemote(remote); err != nil {
return err
}
} else {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("failed to find remote in remotes section"))
}
}
if p.AuthKeyName != "" {
log.Debug("match auth key in profile to auth_keys section")
if key, ok := cfg.AuthKeys[p.AuthKeyName]; ok == true {
if key.Type == "standard" {
p.Provider, err = auth.New(key.Key, nil)
if err != nil {
log.Debugf("failed to create new standard auth provider: %v", err)
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("failed to create new standard auth provider"))
}
} else {
log.Debugf("unknown authentication type %v", key.Type)
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("unknown authentication type"))
}
} else {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("failed to find auth_key in auth_keys section"))
}
}
if p.AuthRemote.AuthKeyName != "" {
log.Debug("match auth remote key in profile to auth_keys section")
if key, ok := cfg.AuthKeys[p.AuthRemote.AuthKeyName]; ok == true {
if key.Type == "standard" {
p.RemoteProvider, err = auth.New(key.Key, nil)
if err != nil {
log.Debugf("failed to create new standard auth provider: %v", err)
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("failed to create new standard auth provider"))
}
} else {
log.Debugf("unknown authentication type %v", key.Type)
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("unknown authentication type"))
}
} else {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("failed to find auth_remote's auth_key in auth_keys section"))
}
}
if p.NameWhitelistString != "" {
log.Debug("compiling whitelist regular expression")
rule, err := regexp.Compile(p.NameWhitelistString)
if err != nil {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("failed to compile name whitelist section"))
}
p.NameWhitelist = rule
}
p.ExtensionWhitelist = map[string]bool{}
for _, oid := range p.AllowedExtensions {
p.ExtensionWhitelist[asn1.ObjectIdentifier(oid).String()] = true
}
return nil
}
// updateRemote takes a signing profile and initializes the remote server object
// to the hostname:port combination sent by remote.
func (p *SigningProfile) updateRemote(remote string) error {
if remote != "" {
p.RemoteServer = remote
}
return nil
}
// OverrideRemotes takes a signing configuration and updates the remote server object
// to the hostname:port combination sent by remote
func (p *Signing) OverrideRemotes(remote string) error {
if remote != "" {
var err error
for _, profile := range p.Profiles {
err = profile.updateRemote(remote)
if err != nil {
return err
}
}
err = p.Default.updateRemote(remote)
if err != nil {
return err
}
}
return nil
}
// SetClientCertKeyPairFromFile updates the properties to set client certificates for mutual
// authenticated TLS remote requests
func (p *Signing) SetClientCertKeyPairFromFile(certFile string, keyFile string) error {
if certFile != "" && keyFile != "" {
cert, err := helpers.LoadClientCertificate(certFile, keyFile)
if err != nil {
return err
}
for _, profile := range p.Profiles {
profile.ClientCert = cert
}
p.Default.ClientCert = cert
}
return nil
}
// SetRemoteCAsFromFile reads root CAs from file and updates the properties to set remote CAs for TLS
// remote requests
func (p *Signing) SetRemoteCAsFromFile(caFile string) error {
if caFile != "" {
remoteCAs, err := helpers.LoadPEMCertPool(caFile)
if err != nil {
return err
}
p.SetRemoteCAs(remoteCAs)
}
return nil
}
// SetRemoteCAs updates the properties to set remote CAs for TLS
// remote requests
func (p *Signing) SetRemoteCAs(remoteCAs *x509.CertPool) {
for _, profile := range p.Profiles {
profile.RemoteCAs = remoteCAs
}
p.Default.RemoteCAs = remoteCAs
}
// NeedsRemoteSigner returns true if one of the profiles has a remote set
func (p *Signing) NeedsRemoteSigner() bool {
for _, profile := range p.Profiles {
if profile.RemoteServer != "" {
return true
}
}
if p.Default.RemoteServer != "" {
return true
}
return false
}
// NeedsLocalSigner returns true if one of the profiles doe not have a remote set
func (p *Signing) NeedsLocalSigner() bool {
for _, profile := range p.Profiles {
if profile.RemoteServer == "" {
return true
}
}
if p.Default.RemoteServer == "" {
return true
}
return false
}
// Usages parses the list of key uses in the profile, translating them
// to a list of X.509 key usages and extended key usages. The unknown
// uses are collected into a slice that is also returned.
func (p *SigningProfile) Usages() (ku x509.KeyUsage, eku []x509.ExtKeyUsage, unk []string) {
for _, keyUse := range p.Usage {
if kuse, ok := KeyUsage[keyUse]; ok {
ku |= kuse
} else if ekuse, ok := ExtKeyUsage[keyUse]; ok {
eku = append(eku, ekuse)
} else {
unk = append(unk, keyUse)
}
}
return
}
// A valid profile must be a valid local profile or a valid remote profile.
// A valid local profile has defined at least key usages to be used, and a
// valid local default profile has defined at least a default expiration.
// A valid remote profile (default or not) has remote signer initialized.
// In addition, a remote profile must has a valid auth provider if auth
// key defined.
func (p *SigningProfile) validProfile(isDefault bool) bool {
if p == nil {
return false
}
if p.AuthRemote.RemoteName == "" && p.AuthRemote.AuthKeyName != "" {
log.Debugf("invalid auth remote profile: no remote signer specified")
return false
}
if p.RemoteName != "" {
log.Debugf("validate remote profile")
if p.RemoteServer == "" {
log.Debugf("invalid remote profile: no remote signer specified")
return false
}
if p.AuthKeyName != "" && p.Provider == nil {
log.Debugf("invalid remote profile: auth key name is defined but no auth provider is set")
return false
}
if p.AuthRemote.RemoteName != "" {
log.Debugf("invalid remote profile: auth remote is also specified")
return false
}
} else if p.AuthRemote.RemoteName != "" {
log.Debugf("validate auth remote profile")
if p.RemoteServer == "" {
log.Debugf("invalid auth remote profile: no remote signer specified")
return false
}
if p.AuthRemote.AuthKeyName == "" || p.RemoteProvider == nil {
log.Debugf("invalid auth remote profile: no auth key is defined")
return false
}
} else {
log.Debugf("validate local profile")
if !isDefault {
if len(p.Usage) == 0 {
log.Debugf("invalid local profile: no usages specified")
return false
} else if _, _, unk := p.Usages(); len(unk) == len(p.Usage) {
log.Debugf("invalid local profile: no valid usages")
return false
}
} else {
if p.Expiry == 0 {
log.Debugf("invalid local profile: no expiry set")
return false
}
}
}
log.Debugf("profile is valid")
return true
}
// This checks if the SigningProfile object contains configurations that are only effective with a local signer
// which has access to CA private key.
func (p *SigningProfile) hasLocalConfig() bool {
if p.Usage != nil ||
p.IssuerURL != nil ||
p.OCSP != "" ||
p.ExpiryString != "" ||
p.BackdateString != "" ||
p.CAConstraint.IsCA != false ||
!p.NotBefore.IsZero() ||
!p.NotAfter.IsZero() ||
p.NameWhitelistString != "" ||
len(p.CTLogServers) != 0 {
return true
}
return false
}
// warnSkippedSettings prints a log warning message about skipped settings
// in a SigningProfile, usually due to remote signer.
func (p *Signing) warnSkippedSettings() {
const warningMessage = `The configuration value by "usages", "issuer_urls", "ocsp_url", "crl_url", "ca_constraint", "expiry", "backdate", "not_before", "not_after", "cert_store" and "ct_log_servers" are skipped`
if p == nil {
return
}
if (p.Default.RemoteName != "" || p.Default.AuthRemote.RemoteName != "") && p.Default.hasLocalConfig() {
log.Warning("default profile points to a remote signer: ", warningMessage)
}
for name, profile := range p.Profiles {
if (profile.RemoteName != "" || profile.AuthRemote.RemoteName != "") && profile.hasLocalConfig() {
log.Warningf("Profiles[%s] points to a remote signer: %s", name, warningMessage)
}
}
}
// Signing codifies the signature configuration policy for a CA.
type Signing struct {
Profiles map[string]*SigningProfile `json:"profiles"`
Default *SigningProfile `json:"default"`
}
// Config stores configuration information for the CA.
type Config struct {
Signing *Signing `json:"signing"`
OCSP *ocspConfig.Config `json:"ocsp"`
AuthKeys map[string]AuthKey `json:"auth_keys,omitempty"`
Remotes map[string]string `json:"remotes,omitempty"`
}
// Valid ensures that Config is a valid configuration. It should be
// called immediately after parsing a configuration file.
func (c *Config) Valid() bool {
return c.Signing.Valid()
}
// Valid checks the signature policies, ensuring they are valid
// policies. A policy is valid if it has defined at least key usages
// to be used, and a valid default profile has defined at least a
// default expiration.
func (p *Signing) Valid() bool {
if p == nil {
return false
}
log.Debugf("validating configuration")
if !p.Default.validProfile(true) {
log.Debugf("default profile is invalid")
return false
}
for _, sp := range p.Profiles {
if !sp.validProfile(false) {
log.Debugf("invalid profile")
return false
}
}
p.warnSkippedSettings()
return true
}
// KeyUsage contains a mapping of string names to key usages.
var KeyUsage = map[string]x509.KeyUsage{
"signing": x509.KeyUsageDigitalSignature,
"digital signature": x509.KeyUsageDigitalSignature,
"content commitment": x509.KeyUsageContentCommitment,
"key encipherment": x509.KeyUsageKeyEncipherment,
"key agreement": x509.KeyUsageKeyAgreement,
"data encipherment": x509.KeyUsageDataEncipherment,
"cert sign": x509.KeyUsageCertSign,
"crl sign": x509.KeyUsageCRLSign,
"encipher only": x509.KeyUsageEncipherOnly,
"decipher only": x509.KeyUsageDecipherOnly,
}
// ExtKeyUsage contains a mapping of string names to extended key
// usages.
var ExtKeyUsage = map[string]x509.ExtKeyUsage{
"any": x509.ExtKeyUsageAny,
"server auth": x509.ExtKeyUsageServerAuth,
"client auth": x509.ExtKeyUsageClientAuth,
"code signing": x509.ExtKeyUsageCodeSigning,
"email protection": x509.ExtKeyUsageEmailProtection,
"s/mime": x509.ExtKeyUsageEmailProtection,
"ipsec end system": x509.ExtKeyUsageIPSECEndSystem,
"ipsec tunnel": x509.ExtKeyUsageIPSECTunnel,
"ipsec user": x509.ExtKeyUsageIPSECUser,
"timestamping": x509.ExtKeyUsageTimeStamping,
"ocsp signing": x509.ExtKeyUsageOCSPSigning,
"microsoft sgc": x509.ExtKeyUsageMicrosoftServerGatedCrypto,
"netscape sgc": x509.ExtKeyUsageNetscapeServerGatedCrypto,
}
// An AuthKey contains an entry for a key used for authentication.
type AuthKey struct {
// Type contains information needed to select the appropriate
// constructor. For example, "standard" for HMAC-SHA-256,
// "standard-ip" for HMAC-SHA-256 incorporating the client's
// IP.
Type string `json:"type"`
// Key contains the key information, such as a hex-encoded
// HMAC key.
Key string `json:"key"`
}
// DefaultConfig returns a default configuration specifying basic key
// usage and a 1 year expiration time. The key usages chosen are
// signing, key encipherment, client auth and server auth.
func DefaultConfig() *SigningProfile {
d := helpers.OneYear
return &SigningProfile{
Usage: []string{"signing", "key encipherment", "server auth", "client auth"},
Expiry: d,
ExpiryString: "8760h",
}
}
// LoadFile attempts to load the configuration file stored at the path
// and returns the configuration. On error, it returns nil.
func LoadFile(path string) (*Config, error) {
log.Debugf("loading configuration file from %s", path)
if path == "" {
return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path"))
}
body, err := ioutil.ReadFile(path)
if err != nil {
return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file"))
}
return LoadConfig(body)
}
// LoadConfig attempts to load the configuration from a byte slice.
// On error, it returns nil.
func LoadConfig(config []byte) (*Config, error) {
var cfg = &Config{}
err := json.Unmarshal(config, &cfg)
if err != nil {
return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
errors.New("failed to unmarshal configuration: "+err.Error()))
}
if cfg.Signing == nil {
return nil, errors.New("No \"signing\" field present")
}
if cfg.Signing.Default == nil {
log.Debugf("no default given: using default config")
cfg.Signing.Default = DefaultConfig()
} else {
if err := cfg.Signing.Default.populate(cfg); err != nil {
return nil, err
}
}
for k := range cfg.Signing.Profiles {
if err := cfg.Signing.Profiles[k].populate(cfg); err != nil {
return nil, err
}
}
if !cfg.Valid() {
return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid configuration"))
}
log.Debugf("configuration ok")
return cfg, nil
}

View File

@ -0,0 +1,537 @@
package config
import (
"encoding/json"
"fmt"
"testing"
"time"
)
var expiry = 1 * time.Minute
var invalidProfileConfig = &Config{
Signing: &Signing{
Profiles: map[string]*SigningProfile{
"invalid": {
Usage: []string{"wiretapping"},
Expiry: expiry,
},
"empty": {},
},
Default: &SigningProfile{
Usage: []string{"digital signature"},
Expiry: expiry,
},
},
}
var invalidDefaultConfig = &Config{
Signing: &Signing{
Profiles: map[string]*SigningProfile{
"key usage": {
Usage: []string{"digital signature"},
},
},
Default: &SigningProfile{
Usage: []string{"s/mime"},
},
},
}
var validConfig = &Config{
Signing: &Signing{
Profiles: map[string]*SigningProfile{
"valid": {
Usage: []string{"digital signature"},
Expiry: expiry,
},
},
Default: &SigningProfile{
Usage: []string{"digital signature"},
Expiry: expiry,
},
},
}
var validMixedConfig = `
{
"signing": {
"profiles": {
"CA": {
"auth_key": "sample",
"remote": "localhost"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
},
"auth_keys": {
"sample": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}`
var validMinimalRemoteConfig = `
{
"signing": {
"default": {
"auth_key": "sample",
"remote": "localhost"
}
},
"auth_keys": {
"sample": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}`
var validMinimalRemoteConfig2 = `
{
"signing": {
"default": {
"auth_remote":{
"auth_key": "sample",
"remote": "localhost"
}
}
},
"auth_keys": {
"sample": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}`
var invalidConflictRemoteConfig = `
{
"signing": {
"default": {
"auth_remote":{
"auth_key": "sample",
"remote": "localhost"
},
"remote": "localhost"
}
},
"auth_keys": {
"sample": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}`
var invalidRemoteConfig = `
{
"signing": {
"default": {
"auth_remotes_typos":{
"auth_key": "sample",
"remote": "localhost"
}
}
},
"auth_keys": {
"sample": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}`
var invalidAuthRemoteConfigMissingRemote = `
{
"signing": {
"default": {
"auth_remote":{
"auth_key": "sample"
}
}
},
"auth_keys": {
"sample": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}`
var invalidAuthRemoteConfigMissingKey = `
{
"signing": {
"default": {
"auth_remote":{
"remote": "localhost"
}
}
},
"auth_keys": {
"sample": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}`
var validMinimalLocalConfig = `
{
"signing": {
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
}
}`
var validLocalConfigsWithCAConstraint = []string{
`{
"signing": {
"default": {
"usages": ["digital signature", "email protection"],
"ca_constraint": { "is_ca": true },
"expiry": "8000h"
}
}
}`,
`{
"signing": {
"default": {
"usages": ["digital signature", "email protection"],
"ca_constraint": { "is_ca": true, "max_path_len": 1 },
"expiry": "8000h"
}
}
}`,
`{
"signing": {
"default": {
"usages": ["digital signature", "email protection"],
"ca_constraint": { "is_ca": true, "max_path_len_zero": true },
"expiry": "8000h"
}
}
}`,
}
func TestInvalidProfile(t *testing.T) {
if invalidProfileConfig.Signing.Profiles["invalid"].validProfile(false) {
t.Fatal("invalid profile accepted as valid")
}
if invalidProfileConfig.Signing.Profiles["empty"].validProfile(false) {
t.Fatal("invalid profile accepted as valid")
}
if invalidProfileConfig.Valid() {
t.Fatal("invalid config accepted as valid")
}
if !invalidProfileConfig.Signing.Profiles["invalid"].validProfile(true) {
t.Fatal("invalid profile should be a valid default profile")
}
}
func TestRemoteProfiles(t *testing.T) {
var validRemoteProfile = &SigningProfile{
RemoteName: "localhost",
RemoteServer: "localhost:8080",
}
var invalidRemoteProfile = &SigningProfile{
RemoteName: "localhost",
}
var invalidRemoteAuthProfile = &SigningProfile{
RemoteName: "localhost",
RemoteServer: "localhost:8080",
AuthKeyName: "blahblah",
}
if !validRemoteProfile.validProfile(true) ||
!validRemoteProfile.validProfile(false) {
t.Fatal("valid remote profile is rejected.")
}
if invalidRemoteProfile.validProfile(true) ||
invalidRemoteProfile.validProfile(false) {
t.Fatal("invalid remote profile is accepted.")
}
if invalidRemoteAuthProfile.validProfile(true) ||
invalidRemoteAuthProfile.validProfile(false) {
t.Fatal("invalid remote profile is accepted.")
}
}
func TestInvalidDefault(t *testing.T) {
if invalidDefaultConfig.Signing.Default.validProfile(true) {
t.Fatal("invalid default accepted as valid")
}
if invalidDefaultConfig.Valid() {
t.Fatal("invalid config accepted as valid")
}
if !invalidDefaultConfig.Signing.Default.validProfile(false) {
t.Fatal("invalid default profile should be a valid profile")
}
}
func TestValidConfig(t *testing.T) {
if !validConfig.Valid() {
t.Fatal("Valid config is not valid")
}
bytes, _ := json.Marshal(validConfig)
fmt.Printf("%v", string(bytes))
}
func TestDefaultConfig(t *testing.T) {
if !DefaultConfig().validProfile(false) {
t.Fatal("global default signing profile should be a valid profile.")
}
if !DefaultConfig().validProfile(true) {
t.Fatal("global default signing profile should be a valid default profile")
}
}
func TestParse(t *testing.T) {
var validProfiles = []*SigningProfile{
{
ExpiryString: "8760h",
},
{
ExpiryString: "168h",
},
{
ExpiryString: "300s",
},
}
var invalidProfiles = []*SigningProfile{
nil,
{},
{
ExpiryString: "",
},
{
ExpiryString: "365d",
},
{
ExpiryString: "1y",
},
{
ExpiryString: "one year",
},
}
for _, p := range validProfiles {
if p.populate(nil) != nil {
t.Fatalf("Failed to parse ExpiryString=%s", p.ExpiryString)
}
}
for _, p := range invalidProfiles {
if p.populate(nil) == nil {
if p != nil {
t.Fatalf("ExpiryString=%s should not be parseable", p.ExpiryString)
}
t.Fatalf("Nil profile should not be parseable")
}
}
}
func TestLoadFile(t *testing.T) {
validConfigFiles := []string{
"testdata/valid_config.json",
"testdata/valid_config_auth.json",
"testdata/valid_config_no_default.json",
"testdata/valid_config_auth_no_default.json",
}
for _, configFile := range validConfigFiles {
_, err := LoadFile(configFile)
if err != nil {
t.Fatal("Load valid config file failed.", configFile, "error is ", err)
}
}
}
func TestLoadInvalidConfigFile(t *testing.T) {
invalidConfigFiles := []string{"", "testdata/no_such_file",
"testdata/invalid_default.json",
"testdata/invalid_profiles.json",
"testdata/invalid_usage.json",
"testdata/invalid_config.json",
"testdata/invalid_auth.json",
"testdata/invalid_auth_bad_key.json",
"testdata/invalid_no_auth_keys.json",
"testdata/invalid_remote.json",
"testdata/invalid_no_remotes.json",
}
for _, configFile := range invalidConfigFiles {
_, err := LoadFile(configFile)
if err == nil {
t.Fatal("Invalid config is loaded.", configFile)
}
}
}
func TestNeedLocalSigner(t *testing.T) {
c, err := LoadConfig([]byte(validMixedConfig))
if err != nil {
t.Fatal("load valid config failed:", err)
}
// This signing config needs both local signer and remote signer.
if c.Signing.NeedsLocalSigner() != true {
t.Fatal("incorrect NeedsLocalSigner().")
}
if c.Signing.NeedsRemoteSigner() != true {
t.Fatal("incorrect NeedsRemoteSigner()")
}
remoteConfig, err := LoadConfig([]byte(validMinimalRemoteConfig))
if err != nil {
t.Fatal("Load valid config failed:", err)
}
if remoteConfig.Signing.NeedsLocalSigner() != false {
t.Fatal("incorrect NeedsLocalSigner().")
}
if remoteConfig.Signing.NeedsRemoteSigner() != true {
t.Fatal("incorrect NeedsRemoteSigner().")
}
localConfig, err := LoadConfig([]byte(validMinimalLocalConfig))
if localConfig.Signing.NeedsLocalSigner() != true {
t.Fatal("incorrect NeedsLocalSigner().")
}
if localConfig.Signing.NeedsRemoteSigner() != false {
t.Fatal("incorrect NeedsRemoteSigner().")
}
if err != nil {
t.Fatal(err)
}
}
func TestOverrideRemotes(t *testing.T) {
c, err := LoadConfig([]byte(validMixedConfig))
if err != nil {
t.Fatal("load valid config failed:", err)
}
host := "localhost:8888"
c.Signing.OverrideRemotes(host)
if c.Signing.Default.RemoteServer != host {
t.Fatal("should override default profile's RemoteServer")
}
for _, p := range c.Signing.Profiles {
if p.RemoteServer != host {
t.Fatal("failed to override profile's RemoteServer")
}
}
}
func TestAuthRemoteConfig(t *testing.T) {
c, err := LoadConfig([]byte(validMinimalRemoteConfig2))
if err != nil {
t.Fatal("load valid config failed:", err)
}
if c.Signing.Default.RemoteServer != "127.0.0.1:8888" {
t.Fatal("load valid config failed: incorrect remote server")
}
host := "localhost:8888"
c.Signing.OverrideRemotes(host)
if c.Signing.Default.RemoteServer != host {
t.Fatal("should override default profile's RemoteServer")
}
for _, p := range c.Signing.Profiles {
if p.RemoteServer != host {
t.Fatal("failed to override profile's RemoteServer")
}
}
}
func TestDuplicateRemoteConfig(t *testing.T) {
_, err := LoadConfig([]byte(invalidConflictRemoteConfig))
if err == nil {
t.Fatal("fail to reject invalid config")
}
}
func TestBadAuthRemoteConfig(t *testing.T) {
_, err := LoadConfig([]byte(invalidRemoteConfig))
if err == nil {
t.Fatal("load invalid config should failed")
}
_, err = LoadConfig([]byte(invalidAuthRemoteConfigMissingRemote))
if err == nil {
t.Fatal("load invalid config should failed")
}
_, err = LoadConfig([]byte(invalidAuthRemoteConfigMissingKey))
if err == nil {
t.Fatal("load invalid config should failed")
}
var p *Signing
if p.Valid() {
t.Fatal("nil Signing config should be invalid")
}
}
func TestValidCAConstraint(t *testing.T) {
for _, config := range validLocalConfigsWithCAConstraint {
_, err := LoadConfig([]byte(config))
if err != nil {
t.Fatal("can't parse valid ca constraint")
}
}
}

View File

@ -0,0 +1,27 @@
{
"signing": {
"profiles": {
"CA": {
"remote": "localhost",
"auth_key": "garbage"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
},
"auth_keys": {
"garbage": {
"type":"stadardo",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}

View File

@ -0,0 +1,27 @@
{
"signing": {
"profiles": {
"CA": {
"remote": "localhost",
"auth_key": "garbage"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
},
"auth_keys": {
"garbage": {
"type":"standard",
"key":"BAD_KEY"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}

View File

@ -0,0 +1,17 @@
{
"signing": {
"profiles": {
"CA": {
"usages": ["cert sign"],
"expiry": "720h"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
}
}
}

View File

@ -0,0 +1,18 @@
{
"signing": {
"profiles": {
"CA": {
"usages": ["cert sign"],
"expiry": "720h"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "invalid_expiry"
}
}
}

View File

@ -0,0 +1,23 @@
{
"signing": {
"profiles": {
"CA": {
"remote": "localhost",
"auth_key": "garbage"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
},
"auth_keys": {
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}

View File

@ -0,0 +1,24 @@
{
"signing": {
"profiles": {
"CA": {
"auth_key": "garbage",
"remote": "localhoster"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
},
"auth_keys": {
"garbage": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
}
}

View File

@ -0,0 +1,18 @@
{
"signing": {
"profiles": {
"CA": {
"usages": ["cert sign"],
"expiry": "720h"
},
"email": {
"usages": ["s/mime"],
"expiry": "invalid_expiry"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
}
}

View File

@ -0,0 +1,27 @@
{
"signing": {
"profiles": {
"CA": {
"auth_key": "garbage",
"remote": "localhoster"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
},
"auth_keys": {
"garbage": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}

View File

@ -0,0 +1,18 @@
{
"signing": {
"profiles": {
"CA": {
"usages": ["cert sign"],
"expiry": "720h"
},
"email": {
"usages": ["BAD_USAGE"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
}
}

View File

@ -0,0 +1,24 @@
{
"signing": {
"profiles": {
"CA": {
"usages": ["cert sign"],
"expiry": "720h"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
},
"auth_key": {
"garbage": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
}
}

View File

@ -0,0 +1,29 @@
{
"signing": {
"profiles": {
"CA": {
"usages": ["cert sign"],
"expiry": "720h",
"auth_key": "garbage",
"remote": "localhost"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
},
"default": {
"usages": ["digital signature", "email protection"],
"expiry": "8000h"
}
},
"auth_keys": {
"garbage": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}

View File

@ -0,0 +1,19 @@
{
"signing": {
"profiles": {
"CA": {
"auth_key": "garbage",
"remote": "localhost"
}
}
},
"auth_keys": {
"garbage": {
"type":"standard",
"key":"0123456789ABCDEF0123456789ABCDEF"
}
},
"remotes": {
"localhost": "127.0.0.1:8888"
}
}

View File

@ -0,0 +1,14 @@
{
"signing": {
"profiles": {
"CA": {
"usages": ["cert sign"],
"expiry": "720h"
},
"email": {
"usages": ["s/mime"],
"expiry": "720h"
}
}
}
}

View File

@ -0,0 +1,188 @@
// Package pkcs7 implements the subset of the CMS PKCS #7 datatype that is typically
// used to package certificates and CRLs. Using openssl, every certificate converted
// to PKCS #7 format from another encoding such as PEM conforms to this implementation.
// reference: https://www.openssl.org/docs/man1.1.0/apps/crl2pkcs7.html
//
// PKCS #7 Data type, reference: https://tools.ietf.org/html/rfc2315
//
// The full pkcs#7 cryptographic message syntax allows for cryptographic enhancements,
// for example data can be encrypted and signed and then packaged through pkcs#7 to be
// sent over a network and then verified and decrypted. It is asn1, and the type of
// PKCS #7 ContentInfo, which comprises the PKCS #7 structure, is:
//
// ContentInfo ::= SEQUENCE {
// contentType ContentType,
// content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
// }
//
// There are 6 possible ContentTypes, data, signedData, envelopedData,
// signedAndEnvelopedData, digestedData, and encryptedData. Here signedData, Data, and encrypted
// Data are implemented, as the degenerate case of signedData without a signature is the typical
// format for transferring certificates and CRLS, and Data and encryptedData are used in PKCS #12
// formats.
// The ContentType signedData has the form:
//
//
// signedData ::= SEQUENCE {
// version Version,
// digestAlgorithms DigestAlgorithmIdentifiers,
// contentInfo ContentInfo,
// certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL
// crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
// signerInfos SignerInfos
// }
//
// As of yet signerInfos and digestAlgorithms are not parsed, as they are not relevant to
// this system's use of PKCS #7 data. Version is an integer type, note that PKCS #7 is
// recursive, this second layer of ContentInfo is similar ignored for our degenerate
// usage. The ExtendedCertificatesAndCertificates type consists of a sequence of choices
// between PKCS #6 extended certificates and x509 certificates. Any sequence consisting
// of any number of extended certificates is not yet supported in this implementation.
//
// The ContentType Data is simply a raw octet string and is parsed directly into a Go []byte slice.
//
// The ContentType encryptedData is the most complicated and its form can be gathered by
// the go type below. It essentially contains a raw octet string of encrypted data and an
// algorithm identifier for use in decrypting this data.
package pkcs7
import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"errors"
cferr "github.com/cloudflare/cfssl/errors"
)
// Types used for asn1 Unmarshaling.
type signedData struct {
Version int
DigestAlgorithms asn1.RawValue
ContentInfo asn1.RawValue
Certificates asn1.RawValue `asn1:"optional" asn1:"tag:0"`
Crls asn1.RawValue `asn1:"optional"`
SignerInfos asn1.RawValue
}
type initPKCS7 struct {
Raw asn1.RawContent
ContentType asn1.ObjectIdentifier
Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
}
// Object identifier strings of the three implemented PKCS7 types.
const (
ObjIDData = "1.2.840.113549.1.7.1"
ObjIDSignedData = "1.2.840.113549.1.7.2"
ObjIDEncryptedData = "1.2.840.113549.1.7.6"
)
// PKCS7 represents the ASN1 PKCS #7 Content type. It contains one of three
// possible types of Content objects, as denoted by the object identifier in
// the ContentInfo field, the other two being nil. SignedData
// is the degenerate SignedData Content info without signature used
// to hold certificates and crls. Data is raw bytes, and EncryptedData
// is as defined in PKCS #7 standard.
type PKCS7 struct {
Raw asn1.RawContent
ContentInfo string
Content Content
}
// Content implements three of the six possible PKCS7 data types. Only one is non-nil.
type Content struct {
Data []byte
SignedData SignedData
EncryptedData EncryptedData
}
// SignedData defines the typical carrier of certificates and crls.
type SignedData struct {
Raw asn1.RawContent
Version int
Certificates []*x509.Certificate
Crl *pkix.CertificateList
}
// Data contains raw bytes. Used as a subtype in PKCS12.
type Data struct {
Bytes []byte
}
// EncryptedData contains encrypted data. Used as a subtype in PKCS12.
type EncryptedData struct {
Raw asn1.RawContent
Version int
EncryptedContentInfo EncryptedContentInfo
}
// EncryptedContentInfo is a subtype of PKCS7EncryptedData.
type EncryptedContentInfo struct {
Raw asn1.RawContent
ContentType asn1.ObjectIdentifier
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
EncryptedContent []byte `asn1:"tag:0,optional"`
}
// ParsePKCS7 attempts to parse the DER encoded bytes of a
// PKCS7 structure.
func ParsePKCS7(raw []byte) (msg *PKCS7, err error) {
var pkcs7 initPKCS7
_, err = asn1.Unmarshal(raw, &pkcs7)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
}
msg = new(PKCS7)
msg.Raw = pkcs7.Raw
msg.ContentInfo = pkcs7.ContentType.String()
switch {
case msg.ContentInfo == ObjIDData:
msg.ContentInfo = "Data"
_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &msg.Content.Data)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
}
case msg.ContentInfo == ObjIDSignedData:
msg.ContentInfo = "SignedData"
var signedData signedData
_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &signedData)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
}
if len(signedData.Certificates.Bytes) != 0 {
msg.Content.SignedData.Certificates, err = x509.ParseCertificates(signedData.Certificates.Bytes)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
}
}
if len(signedData.Crls.Bytes) != 0 {
msg.Content.SignedData.Crl, err = x509.ParseDERCRL(signedData.Crls.Bytes)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
}
}
msg.Content.SignedData.Version = signedData.Version
msg.Content.SignedData.Raw = pkcs7.Content.Bytes
case msg.ContentInfo == ObjIDEncryptedData:
msg.ContentInfo = "EncryptedData"
var encryptedData EncryptedData
_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &encryptedData)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
}
if encryptedData.Version != 0 {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Only support for PKCS #7 encryptedData version 0"))
}
msg.Content.EncryptedData = encryptedData
default:
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Attempt to parse PKCS# 7 Content not of type data, signed data or encrypted data"))
}
return msg, nil
}

432
vendor/github.com/cloudflare/cfssl/csr/csr.go generated vendored Normal file
View File

@ -0,0 +1,432 @@
// Package csr implements certificate requests for CFSSL.
package csr
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"errors"
"net"
"net/mail"
"strings"
cferr "github.com/cloudflare/cfssl/errors"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/log"
)
const (
curveP256 = 256
curveP384 = 384
curveP521 = 521
)
// A Name contains the SubjectInfo fields.
type Name struct {
C string // Country
ST string // State
L string // Locality
O string // OrganisationName
OU string // OrganisationalUnitName
SerialNumber string
}
// A KeyRequest is a generic request for a new key.
type KeyRequest interface {
Algo() string
Size() int
Generate() (crypto.PrivateKey, error)
SigAlgo() x509.SignatureAlgorithm
}
// A BasicKeyRequest contains the algorithm and key size for a new private key.
type BasicKeyRequest struct {
A string `json:"algo" yaml:"algo"`
S int `json:"size" yaml:"size"`
}
// NewBasicKeyRequest returns a default BasicKeyRequest.
func NewBasicKeyRequest() *BasicKeyRequest {
return &BasicKeyRequest{"ecdsa", curveP256}
}
// Algo returns the requested key algorithm represented as a string.
func (kr *BasicKeyRequest) Algo() string {
return kr.A
}
// Size returns the requested key size.
func (kr *BasicKeyRequest) Size() int {
return kr.S
}
// Generate generates a key as specified in the request. Currently,
// only ECDSA and RSA are supported.
func (kr *BasicKeyRequest) Generate() (crypto.PrivateKey, error) {
log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo(), kr.Size())
switch kr.Algo() {
case "rsa":
if kr.Size() < 2048 {
return nil, errors.New("RSA key is too weak")
}
if kr.Size() > 8192 {
return nil, errors.New("RSA key size too large")
}
return rsa.GenerateKey(rand.Reader, kr.Size())
case "ecdsa":
var curve elliptic.Curve
switch kr.Size() {
case curveP256:
curve = elliptic.P256()
case curveP384:
curve = elliptic.P384()
case curveP521:
curve = elliptic.P521()
default:
return nil, errors.New("invalid curve")
}
return ecdsa.GenerateKey(curve, rand.Reader)
default:
return nil, errors.New("invalid algorithm")
}
}
// SigAlgo returns an appropriate X.509 signature algorithm given the
// key request's type and size.
func (kr *BasicKeyRequest) SigAlgo() x509.SignatureAlgorithm {
switch kr.Algo() {
case "rsa":
switch {
case kr.Size() >= 4096:
return x509.SHA512WithRSA
case kr.Size() >= 3072:
return x509.SHA384WithRSA
case kr.Size() >= 2048:
return x509.SHA256WithRSA
default:
return x509.SHA1WithRSA
}
case "ecdsa":
switch kr.Size() {
case curveP521:
return x509.ECDSAWithSHA512
case curveP384:
return x509.ECDSAWithSHA384
case curveP256:
return x509.ECDSAWithSHA256
default:
return x509.ECDSAWithSHA1
}
default:
return x509.UnknownSignatureAlgorithm
}
}
// CAConfig is a section used in the requests initialising a new CA.
type CAConfig struct {
PathLength int `json:"pathlen" yaml:"pathlen"`
PathLenZero bool `json:"pathlenzero" yaml:"pathlenzero"`
Expiry string `json:"expiry" yaml:"expiry"`
Backdate string `json:"backdate" yaml:"backdate"`
}
// A CertificateRequest encapsulates the API interface to the
// certificate request functionality.
type CertificateRequest struct {
CN string
Names []Name `json:"names" yaml:"names"`
Hosts []string `json:"hosts" yaml:"hosts"`
KeyRequest KeyRequest `json:"key,omitempty" yaml:"key,omitempty"`
CA *CAConfig `json:"ca,omitempty" yaml:"ca,omitempty"`
SerialNumber string `json:"serialnumber,omitempty" yaml:"serialnumber,omitempty"`
}
// New returns a new, empty CertificateRequest with a
// BasicKeyRequest.
func New() *CertificateRequest {
return &CertificateRequest{
KeyRequest: NewBasicKeyRequest(),
}
}
// appendIf appends to a if s is not an empty string.
func appendIf(s string, a *[]string) {
if s != "" {
*a = append(*a, s)
}
}
// Name returns the PKIX name for the request.
func (cr *CertificateRequest) Name() pkix.Name {
var name pkix.Name
name.CommonName = cr.CN
for _, n := range cr.Names {
appendIf(n.C, &name.Country)
appendIf(n.ST, &name.Province)
appendIf(n.L, &name.Locality)
appendIf(n.O, &name.Organization)
appendIf(n.OU, &name.OrganizationalUnit)
}
name.SerialNumber = cr.SerialNumber
return name
}
// BasicConstraints CSR information RFC 5280, 4.2.1.9
type BasicConstraints struct {
IsCA bool `asn1:"optional"`
MaxPathLen int `asn1:"optional,default:-1"`
}
// ParseRequest takes a certificate request and generates a key and
// CSR from it. It does no validation -- caveat emptor. It will,
// however, fail if the key request is not valid (i.e., an unsupported
// curve or RSA key size). The lack of validation was specifically
// chosen to allow the end user to define a policy and validate the
// request appropriately before calling this function.
func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
log.Info("received CSR")
if req.KeyRequest == nil {
req.KeyRequest = NewBasicKeyRequest()
}
log.Infof("generating key: %s-%d", req.KeyRequest.Algo(), req.KeyRequest.Size())
priv, err := req.KeyRequest.Generate()
if err != nil {
err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err)
return
}
switch priv := priv.(type) {
case *rsa.PrivateKey:
key = x509.MarshalPKCS1PrivateKey(priv)
block := pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: key,
}
key = pem.EncodeToMemory(&block)
case *ecdsa.PrivateKey:
key, err = x509.MarshalECPrivateKey(priv)
if err != nil {
err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err)
return
}
block := pem.Block{
Type: "EC PRIVATE KEY",
Bytes: key,
}
key = pem.EncodeToMemory(&block)
default:
panic("Generate should have failed to produce a valid key.")
}
csr, err = Generate(priv.(crypto.Signer), req)
if err != nil {
log.Errorf("failed to generate a CSR: %v", err)
err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
}
return
}
// ExtractCertificateRequest extracts a CertificateRequest from
// x509.Certificate. It is aimed to used for generating a new certificate
// from an existing certificate. For a root certificate, the CA expiry
// length is calculated as the duration between cert.NotAfter and cert.NotBefore.
func ExtractCertificateRequest(cert *x509.Certificate) *CertificateRequest {
req := New()
req.CN = cert.Subject.CommonName
req.Names = getNames(cert.Subject)
req.Hosts = getHosts(cert)
req.SerialNumber = cert.Subject.SerialNumber
if cert.IsCA {
req.CA = new(CAConfig)
// CA expiry length is calculated based on the input cert
// issue date and expiry date.
req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String()
req.CA.PathLength = cert.MaxPathLen
req.CA.PathLenZero = cert.MaxPathLenZero
}
return req
}
func getHosts(cert *x509.Certificate) []string {
var hosts []string
for _, ip := range cert.IPAddresses {
hosts = append(hosts, ip.String())
}
for _, dns := range cert.DNSNames {
hosts = append(hosts, dns)
}
for _, email := range cert.EmailAddresses {
hosts = append(hosts, email)
}
return hosts
}
// getNames returns an array of Names from the certificate
// It onnly cares about Country, Organization, OrganizationalUnit, Locality, Province
func getNames(sub pkix.Name) []Name {
// anonymous func for finding the max of a list of interger
max := func(v1 int, vn ...int) (max int) {
max = v1
for i := 0; i < len(vn); i++ {
if vn[i] > max {
max = vn[i]
}
}
return max
}
nc := len(sub.Country)
norg := len(sub.Organization)
nou := len(sub.OrganizationalUnit)
nl := len(sub.Locality)
np := len(sub.Province)
n := max(nc, norg, nou, nl, np)
names := make([]Name, n)
for i := range names {
if i < nc {
names[i].C = sub.Country[i]
}
if i < norg {
names[i].O = sub.Organization[i]
}
if i < nou {
names[i].OU = sub.OrganizationalUnit[i]
}
if i < nl {
names[i].L = sub.Locality[i]
}
if i < np {
names[i].ST = sub.Province[i]
}
}
return names
}
// A Generator is responsible for validating certificate requests.
type Generator struct {
Validator func(*CertificateRequest) error
}
// ProcessRequest validates and processes the incoming request. It is
// a wrapper around a validator and the ParseRequest function.
func (g *Generator) ProcessRequest(req *CertificateRequest) (csr, key []byte, err error) {
log.Info("generate received request")
err = g.Validator(req)
if err != nil {
log.Warningf("invalid request: %v", err)
return nil, nil, err
}
csr, key, err = ParseRequest(req)
if err != nil {
return nil, nil, err
}
return
}
// IsNameEmpty returns true if the name has no identifying information in it.
func IsNameEmpty(n Name) bool {
empty := func(s string) bool { return strings.TrimSpace(s) == "" }
if empty(n.C) && empty(n.ST) && empty(n.L) && empty(n.O) && empty(n.OU) {
return true
}
return false
}
// Regenerate uses the provided CSR as a template for signing a new
// CSR using priv.
func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) {
req, extra, err := helpers.ParseCSR(csr)
if err != nil {
return nil, err
} else if len(extra) > 0 {
return nil, errors.New("csr: trailing data in certificate request")
}
return x509.CreateCertificateRequest(rand.Reader, req, priv)
}
// Generate creates a new CSR from a CertificateRequest structure and
// an existing key. The KeyRequest field is ignored.
func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
sigAlgo := helpers.SignerAlgo(priv)
if sigAlgo == x509.UnknownSignatureAlgorithm {
return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
}
var tpl = x509.CertificateRequest{
Subject: req.Name(),
SignatureAlgorithm: sigAlgo,
}
for i := range req.Hosts {
if ip := net.ParseIP(req.Hosts[i]); ip != nil {
tpl.IPAddresses = append(tpl.IPAddresses, ip)
} else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
tpl.EmailAddresses = append(tpl.EmailAddresses, email.Address)
} else {
tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
}
}
if req.CA != nil {
err = appendCAInfoToCSR(req.CA, &tpl)
if err != nil {
err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err)
return
}
}
csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
if err != nil {
log.Errorf("failed to generate a CSR: %v", err)
err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
return
}
block := pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: csr,
}
log.Info("encoded CSR")
csr = pem.EncodeToMemory(&block)
return
}
// appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR
func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
pathlen := reqConf.PathLength
if pathlen == 0 && !reqConf.PathLenZero {
pathlen = -1
}
val, err := asn1.Marshal(BasicConstraints{true, pathlen})
if err != nil {
return err
}
csr.ExtraExtensions = []pkix.Extension{
{
Id: asn1.ObjectIdentifier{2, 5, 29, 19},
Value: val,
Critical: true,
},
}
return nil
}

744
vendor/github.com/cloudflare/cfssl/csr/csr_test.go generated vendored Normal file
View File

@ -0,0 +1,744 @@
package csr
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"io/ioutil"
"testing"
"github.com/cloudflare/cfssl/errors"
"github.com/cloudflare/cfssl/helpers"
)
//TestNew validate the CertificateRequest created to return with a BasicKeyRequest
//in KeyRequest field
func TestNew(t *testing.T) {
if cr := New(); cr.KeyRequest == nil {
t.Fatalf("Should create a new, empty certificate request with BasicKeyRequest")
}
}
// TestBasicKeyRequest ensures that key generation returns the same type of
// key specified in the BasicKeyRequest.
func TestBasicKeyRequest(t *testing.T) {
kr := NewBasicKeyRequest()
priv, err := kr.Generate()
if err != nil {
t.Fatalf("%v", err)
}
switch priv.(type) {
case *rsa.PrivateKey:
if kr.Algo() != "rsa" {
t.Fatal("RSA key generated, but expected", kr.Algo())
}
case *ecdsa.PrivateKey:
if kr.Algo() != "ecdsa" {
t.Fatal("ECDSA key generated, but expected", kr.Algo())
}
}
}
// TestPKIXName validates building a pkix.Name structure from a
// CertificateRequest.
func TestPKIXName(t *testing.T) {
var cr = &CertificateRequest{
CN: "Test Common Name",
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare, Inc.",
OU: "Systems Engineering",
},
{
C: "GB",
ST: "London",
L: "London",
O: "CloudFlare, Inc",
OU: "Systems Engineering",
},
},
Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
KeyRequest: NewBasicKeyRequest(),
}
name := cr.Name()
if len(name.Country) != 2 {
t.Fatal("Expected two countries in SubjInfo.")
} else if len(name.Province) != 2 {
t.Fatal("Expected two states in SubjInfo.")
} else if len(name.Locality) != 2 {
t.Fatal("Expected two localities in SubjInfo.")
} else if len(name.Country) != 2 {
t.Fatal("Expected two countries in SubjInfo.")
} else if len(name.Organization) != 2 {
t.Fatal("Expected two organization in SubjInfo.")
} else if len(name.OrganizationalUnit) != 2 {
t.Fatal("Expected two organizational units in SubjInfo.")
}
}
// TestParseRequest ensures that a valid certificate request does not
// error.
func TestParseRequest(t *testing.T) {
var cr = &CertificateRequest{
CN: "Test Common Name",
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare, Inc.",
OU: "Systems Engineering",
},
{
C: "GB",
ST: "London",
L: "London",
O: "CloudFlare, Inc",
OU: "Systems Engineering",
},
},
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com"},
KeyRequest: NewBasicKeyRequest(),
}
_, _, err := ParseRequest(cr)
if err != nil {
t.Fatalf("%v", err)
}
}
// TestParseRequestCA ensures that a valid CA certificate request does not
// error and the resulting CSR includes the BasicConstraint extension
func TestParseRequestCA(t *testing.T) {
var cr = &CertificateRequest{
CN: "Test Common Name",
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare, Inc.",
OU: "Systems Engineering",
},
{
C: "GB",
ST: "London",
L: "London",
O: "CloudFlare, Inc",
OU: "Systems Engineering",
},
},
CA: &CAConfig{
PathLength: 0,
PathLenZero: true,
},
KeyRequest: NewBasicKeyRequest(),
}
csrBytes, _, err := ParseRequest(cr)
if err != nil {
t.Fatalf("%v", err)
}
block, _ := pem.Decode(csrBytes)
if block == nil {
t.Fatalf("%v", err)
}
if block.Type != "CERTIFICATE REQUEST" {
t.Fatalf("Incorrect block type: %s", block.Type)
}
csr, err := x509.ParseCertificateRequest(block.Bytes)
if err != nil {
t.Fatalf("%v", err)
}
found := false
for _, ext := range csr.Extensions {
if ext.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
found = true
break
}
}
if !found {
t.Fatalf("CSR did not include BasicConstraint Extension")
}
}
// TestParseRequestCANoPathlen ensures that a valid CA certificate request
// with an unspecified pathlen does not error and the resulting CSR includes
// the BasicConstraint extension
func TestParseRequestCANoPathlen(t *testing.T) {
var cr = &CertificateRequest{
CN: "Test Common Name",
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare, Inc.",
OU: "Systems Engineering",
},
{
C: "GB",
ST: "London",
L: "London",
O: "CloudFlare, Inc",
OU: "Systems Engineering",
},
},
CA: &CAConfig{
PathLength: 0,
PathLenZero: false,
},
KeyRequest: NewBasicKeyRequest(),
}
csrBytes, _, err := ParseRequest(cr)
if err != nil {
t.Fatalf("%v", err)
}
block, _ := pem.Decode(csrBytes)
if block == nil {
t.Fatalf("%v", err)
}
if block.Type != "CERTIFICATE REQUEST" {
t.Fatalf("Incorrect block type: %s", block.Type)
}
csr, err := x509.ParseCertificateRequest(block.Bytes)
if err != nil {
t.Fatalf("%v", err)
}
found := false
for _, ext := range csr.Extensions {
if ext.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
bc := &BasicConstraints{}
asn1.Unmarshal(ext.Value, bc)
if bc.IsCA == true && bc.MaxPathLen == -1 {
found = true
break
}
}
}
if !found {
t.Fatalf("CSR did not include BasicConstraint Extension")
}
}
func whichCurve(sz int) elliptic.Curve {
switch sz {
case 256:
return elliptic.P256()
case 384:
return elliptic.P384()
case 521:
return elliptic.P521()
}
return nil
}
// TestECGeneration ensures that the proper curve is used depending on
// the bit size specified in a key request and that an appropriate
// signature algorithm is returned.
func TestECGeneration(t *testing.T) {
var eckey *ecdsa.PrivateKey
for _, sz := range []int{256, 384, 521} {
kr := &BasicKeyRequest{"ecdsa", sz}
priv, err := kr.Generate()
if err != nil {
t.Fatalf("%v", err)
}
eckey = priv.(*ecdsa.PrivateKey)
if eckey.Curve != whichCurve(sz) {
t.Fatal("Generated key has wrong curve.")
}
if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm {
t.Fatal("Invalid signature algorithm!")
}
}
}
func TestRSAKeyGeneration(t *testing.T) {
var rsakey *rsa.PrivateKey
for _, sz := range []int{2048, 3072, 4096} {
kr := &BasicKeyRequest{"rsa", sz}
priv, err := kr.Generate()
if err != nil {
t.Fatalf("%v", err)
}
rsakey = priv.(*rsa.PrivateKey)
if rsakey.PublicKey.N.BitLen() != kr.Size() {
t.Fatal("Generated key has wrong size.")
}
if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm {
t.Fatal("Invalid signature algorithm!")
}
}
}
// TestBadBasicKeyRequest ensures that generating a key from a BasicKeyRequest
// fails with an invalid algorithm, or an invalid RSA or ECDSA key
// size. An invalid ECDSA key size is any size other than 256, 384, or
// 521; an invalid RSA key size is any size less than 2048 bits.
func TestBadBasicKeyRequest(t *testing.T) {
kr := &BasicKeyRequest{"yolocrypto", 1024}
if _, err := kr.Generate(); err == nil {
t.Fatal("Key generation should fail with invalid algorithm")
} else if sa := kr.SigAlgo(); sa != x509.UnknownSignatureAlgorithm {
t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
}
kr.A = "ecdsa"
if _, err := kr.Generate(); err == nil {
t.Fatal("Key generation should fail with invalid key size")
} else if sa := kr.SigAlgo(); sa != x509.ECDSAWithSHA1 {
t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
}
kr.A = "rsa"
if _, err := kr.Generate(); err == nil {
t.Fatal("Key generation should fail with invalid key size")
} else if sa := kr.SigAlgo(); sa != x509.SHA1WithRSA {
t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
}
kr = &BasicKeyRequest{"tobig", 9216}
kr.A = "rsa"
if _, err := kr.Generate(); err == nil {
t.Fatal("Key generation should fail with invalid key size")
} else if sa := kr.SigAlgo(); sa != x509.SHA512WithRSA {
t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
}
}
// TestDefaultBasicKeyRequest makes sure that certificate requests without
// explicit key requests fall back to the default key request.
func TestDefaultBasicKeyRequest(t *testing.T) {
var req = &CertificateRequest{
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: "cloudflare.com",
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com"},
}
_, priv, err := ParseRequest(req)
if err != nil {
t.Fatalf("%v", err)
}
// If the default key type changes, this will need to be changed.
block, _ := pem.Decode(priv)
if block == nil {
t.Fatal("Bad private key was generated!")
}
DefaultKeyRequest := NewBasicKeyRequest()
switch block.Type {
case "RSA PRIVATE KEY":
if DefaultKeyRequest.Algo() != "rsa" {
t.Fatal("Invalid default key request.")
}
case "EC PRIVATE KEY":
if DefaultKeyRequest.Algo() != "ecdsa" {
t.Fatal("Invalid default key request.")
}
}
}
// TestRSACertRequest validates parsing a certificate request with an
// RSA key.
func TestRSACertRequest(t *testing.T) {
var req = &CertificateRequest{
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: "cloudflare.com",
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com"},
KeyRequest: &BasicKeyRequest{"rsa", 2048},
}
_, _, err := ParseRequest(req)
if err != nil {
t.Fatalf("%v", err)
}
}
// TestBadCertRequest checks for failure conditions of ParseRequest.
func TestBadCertRequest(t *testing.T) {
var req = &CertificateRequest{
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: "cloudflare.com",
Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
KeyRequest: &BasicKeyRequest{"yolo-crypto", 2048},
}
_, _, err := ParseRequest(req)
if err == nil {
t.Fatal("ParseRequest should fail with a bad key algorithm.")
}
}
// testValidator is a stripped-down validator that checks to make sure
// the request has a common name. It should mimic some of the
// functionality expected in an actual validator.
func testValidator(req *CertificateRequest) error {
if req.CN == "" {
return errors.NewBadRequestMissingParameter("CN")
}
return nil
}
// TestGenerator ensures that a valid request is processed properly
// and returns a certificate request and key.
func TestGenerator(t *testing.T) {
g := &Generator{testValidator}
var req = &CertificateRequest{
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: "cloudflare.com",
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com"},
KeyRequest: &BasicKeyRequest{"rsa", 2048},
}
csrBytes, _, err := g.ProcessRequest(req)
if err != nil {
t.Fatal(err)
}
block, _ := pem.Decode([]byte(csrBytes))
if block == nil {
t.Fatalf("bad CSR in PEM")
}
if block.Type != "CERTIFICATE REQUEST" {
t.Fatalf("bad CSR in PEM")
}
csr, err := x509.ParseCertificateRequest(block.Bytes)
if err != nil {
t.Fatal(err)
}
if len(csr.DNSNames) != 2 {
t.Fatal("SAN parsing error")
}
if len(csr.IPAddresses) != 1 {
t.Fatal("SAN parsing error")
}
if len(csr.EmailAddresses) != 1 {
t.Fatal("SAN parsing error")
}
}
// TestBadGenerator ensures that a request that fails the validator is
// not processed.
func TestBadGenerator(t *testing.T) {
g := &Generator{testValidator}
missingCN := &CertificateRequest{
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
// Missing CN
Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
KeyRequest: &BasicKeyRequest{"rsa", 2048},
}
_, _, err := g.ProcessRequest(missingCN)
if err == nil {
t.Fatalf("Request should have failed.")
}
}
func TestWeakCSR(t *testing.T) {
weakKey := &CertificateRequest{
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: "cloudflare.com",
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com"},
KeyRequest: &BasicKeyRequest{"rsa", 1024},
}
g := &Generator{testValidator}
_, _, err := g.ProcessRequest(weakKey)
if err == nil {
t.Fatalf("Request should have failed.")
}
}
var testEmpty = []struct {
name Name
ok bool
}{
{
Name{},
true,
},
{
Name{C: "OK"},
false,
},
{
Name{ST: "OK"},
false,
},
{
Name{L: "OK"},
false,
},
{
Name{O: "OK"},
false,
},
{
Name{OU: "OK"},
false,
},
}
func TestIsNameEmpty(t *testing.T) {
for i, c := range testEmpty {
if IsNameEmpty(c.name) != c.ok {
t.Fatalf("%d: expected IsNameEmpty to return %v, but have %v", i, c.ok, !c.ok)
}
}
}
func TestGenerate(t *testing.T) {
var req = &CertificateRequest{
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: "cloudflare.com",
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com"},
KeyRequest: &BasicKeyRequest{"ecdsa", 256},
}
key, err := req.KeyRequest.Generate()
if err != nil {
t.Fatalf("%v", err)
}
priv, ok := key.(crypto.Signer)
if !ok {
t.Fatal("Private key is not a signer.")
}
csrPEM, err := Generate(priv, req)
if err != nil {
t.Fatalf("%v", err)
}
csr, _, err := helpers.ParseCSR(csrPEM)
if err != nil {
t.Fatalf("%v", err)
}
if len(csr.DNSNames) != 2 {
t.Fatal("SAN parsing error")
}
if len(csr.IPAddresses) != 1 {
t.Fatal("SAN parsing error")
}
if len(csr.EmailAddresses) != 1 {
t.Fatal("SAN parsing error")
}
}
// TestReGenerate ensures Regenerate() is abel to use the provided CSR as a template for signing a new
// CSR using priv.
func TestReGenerate(t *testing.T) {
var req = &CertificateRequest{
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: "cloudflare.com",
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"},
KeyRequest: &BasicKeyRequest{"ecdsa", 256},
}
_, key, err := ParseRequest(req)
if err != nil {
t.Fatalf("%v", err)
}
priv, err := helpers.ParsePrivateKeyPEM(key)
if err != nil {
t.Fatalf("%v", err)
}
csr, err := Generate(priv, req)
if err != nil {
t.Fatalf("%v", err)
}
if _, _, err = helpers.ParseCSR(csr); err != nil {
t.Fatalf("%v", err)
}
_, err = Regenerate(priv, csr)
if err != nil {
t.Fatalf("%v", err)
}
}
// TestBadReGenerator ensures that a request that fails the ParseCSR is
// not processed.
func TestBadReGenerate(t *testing.T) {
var req = &CertificateRequest{
Names: []Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: "cloudflare.com",
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"},
KeyRequest: &BasicKeyRequest{"ecdsa", 256},
}
_, key, err := ParseRequest(req)
if err != nil {
t.Fatalf("%v", err)
}
priv, err := helpers.ParsePrivateKeyPEM(key)
if err != nil {
t.Fatalf("%v", err)
}
csr, err := Generate(priv, req)
if err != nil {
t.Fatalf("%v", err)
}
block := pem.Block{
Type: "CERTIFICATE REQUEST",
Headers: map[string]string{
"Location": "UCSD",
},
Bytes: csr,
}
csr = pem.EncodeToMemory(&block)
_, err = Regenerate(priv, csr)
if err == nil {
t.Fatalf("%v", err)
}
}
var testECDSACertificateFile = "testdata/test-ecdsa-ca.pem"
func TestExtractCertificateRequest(t *testing.T) {
certPEM, err := ioutil.ReadFile(testECDSACertificateFile)
if err != nil {
t.Fatal(err)
}
// must parse ok
cert, err := helpers.ParseCertificatePEM(certPEM)
if err != nil {
t.Fatal(err)
}
req := ExtractCertificateRequest(cert)
if req.CN != "" {
t.Fatal("Bad Certificate Request!")
}
if len(req.Names) != 1 {
t.Fatal("Bad Certificate Request!")
}
name := req.Names[0]
if name.C != "US" || name.ST != "California" || name.O != "CloudFlare, Inc." ||
name.OU != "Test Certificate Authority" || name.L != "San Francisco" {
t.Fatal("Bad Certificate Request!")
}
if req.CA == nil || req.CA.PathLength != 2 {
t.Fatal("Bad Certificate Request!")
}
}

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICUDCCAfagAwIBAgIIec5PjdpJcNYwCgYIKoZIzj0EAwIwejELMAkGA1UEBhMC
VVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNVBAsTGlRlc3QgQ2Vy
dGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYD
VQQIEwpDYWxpZm9ybmlhMB4XDTE1MTAwODIzMDEwMFoXDTE1MTAwODIzMDYwMFow
ejELMAkGA1UEBhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNV
BAsTGlRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEoCV+bVOLTJMy38j50sc3vE5k41GMRgriFJt0g0OVX8yaOZ93CZTI7Lzf
GbMU+KqWTgOwGhrPvpusep3fjw+dAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud
EwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFDpLhSKBN3njfb6cXQCdRLzCZt0ZMB8G
A1UdIwQYMBaAFDpLhSKBN3njfb6cXQCdRLzCZt0ZMAoGCCqGSM49BAMCA0gAMEUC
IFU3BmzntGGeXZu2qWZx249nYn37S0AkCnQ3rUtI31bdAiEAsPICnZ+GB8yCN26N
OL+N8dHvXiOvZ9/Vl488pyWOccY=
-----END CERTIFICATE-----

46
vendor/github.com/cloudflare/cfssl/errors/doc.go generated vendored Normal file
View File

@ -0,0 +1,46 @@
/*
Package errors provides error types returned in CF SSL.
1. Type Error is intended for errors produced by CF SSL packages.
It formats to a json object that consists of an error message and a 4-digit code for error reasoning.
Example: {"code":1002, "message": "Failed to decode certificate"}
The index of codes are listed below:
1XXX: CertificateError
1000: Unknown
1001: ReadFailed
1002: DecodeFailed
1003: ParseFailed
1100: SelfSigned
12XX: VerifyFailed
121X: CertificateInvalid
1210: NotAuthorizedToSign
1211: Expired
1212: CANotAuthorizedForThisName
1213: TooManyIntermediates
1214: IncompatibleUsage
1220: UnknownAuthority
2XXX: PrivatekeyError
2000: Unknown
2001: ReadFailed
2002: DecodeFailed
2003: ParseFailed
2100: Encrypted
2200: NotRSA
2300: KeyMismatch
2400: GenerationFailed
2500: Unavailable
3XXX: IntermediatesError
4XXX: RootError
5XXX: PolicyError
5100: NoKeyUsages
5200: InvalidPolicy
5300: InvalidRequest
5400: UnknownProfile
6XXX: DialError
2. Type HttpError is intended for CF SSL API to consume. It contains a HTTP status code that will be read and returned
by the API server.
*/
package errors

438
vendor/github.com/cloudflare/cfssl/errors/error.go generated vendored Normal file
View File

@ -0,0 +1,438 @@
package errors
import (
"crypto/x509"
"encoding/json"
"fmt"
)
// Error is the error type usually returned by functions in CF SSL package.
// It contains a 4-digit error code where the most significant digit
// describes the category where the error occurred and the rest 3 digits
// describe the specific error reason.
type Error struct {
ErrorCode int `json:"code"`
Message string `json:"message"`
}
// Category is the most significant digit of the error code.
type Category int
// Reason is the last 3 digits of the error code.
type Reason int
const (
// Success indicates no error occurred.
Success Category = 1000 * iota // 0XXX
// CertificateError indicates a fault in a certificate.
CertificateError // 1XXX
// PrivateKeyError indicates a fault in a private key.
PrivateKeyError // 2XXX
// IntermediatesError indicates a fault in an intermediate.
IntermediatesError // 3XXX
// RootError indicates a fault in a root.
RootError // 4XXX
// PolicyError indicates an error arising from a malformed or
// non-existent policy, or a breach of policy.
PolicyError // 5XXX
// DialError indicates a network fault.
DialError // 6XXX
// APIClientError indicates a problem with the API client.
APIClientError // 7XXX
// OCSPError indicates a problem with OCSP signing
OCSPError // 8XXX
// CSRError indicates a problem with CSR parsing
CSRError // 9XXX
// CTError indicates a problem with the certificate transparency process
CTError // 10XXX
// CertStoreError indicates a problem with the certificate store
CertStoreError // 11XXX
)
// None is a non-specified error.
const (
None Reason = iota
)
// Warning code for a success
const (
BundleExpiringBit int = 1 << iota // 0x01
BundleNotUbiquitousBit // 0x02
)
// Parsing errors
const (
Unknown Reason = iota // X000
ReadFailed // X001
DecodeFailed // X002
ParseFailed // X003
)
// The following represent certificate non-parsing errors, and must be
// specified along with CertificateError.
const (
// SelfSigned indicates that a certificate is self-signed and
// cannot be used in the manner being attempted.
SelfSigned Reason = 100 * (iota + 1) // Code 11XX
// VerifyFailed is an X.509 verification failure. The least two
// significant digits of 12XX is determined as the actual x509
// error is examined.
VerifyFailed // Code 12XX
// BadRequest indicates that the certificate request is invalid.
BadRequest // Code 13XX
// MissingSerial indicates that the profile specified
// 'ClientProvidesSerialNumbers', but the SignRequest did not include a serial
// number.
MissingSerial // Code 14XX
)
const (
certificateInvalid = 10 * (iota + 1) //121X
unknownAuthority //122x
)
// The following represent private-key non-parsing errors, and must be
// specified with PrivateKeyError.
const (
// Encrypted indicates that the private key is a PKCS #8 encrypted
// private key. At this time, CFSSL does not support decrypting
// these keys.
Encrypted Reason = 100 * (iota + 1) //21XX
// NotRSAOrECC indicates that they key is not an RSA or ECC
// private key; these are the only two private key types supported
// at this time by CFSSL.
NotRSAOrECC //22XX
// KeyMismatch indicates that the private key does not match
// the public key or certificate being presented with the key.
KeyMismatch //23XX
// GenerationFailed indicates that a private key could not
// be generated.
GenerationFailed //24XX
// Unavailable indicates that a private key mechanism (such as
// PKCS #11) was requested but support for that mechanism is
// not available.
Unavailable
)
// The following are policy-related non-parsing errors, and must be
// specified along with PolicyError.
const (
// NoKeyUsages indicates that the profile does not permit any
// key usages for the certificate.
NoKeyUsages Reason = 100 * (iota + 1) // 51XX
// InvalidPolicy indicates that policy being requested is not
// a valid policy or does not exist.
InvalidPolicy // 52XX
// InvalidRequest indicates a certificate request violated the
// constraints of the policy being applied to the request.
InvalidRequest // 53XX
// UnknownProfile indicates that the profile does not exist.
UnknownProfile // 54XX
UnmatchedWhitelist // 55xx
)
// The following are API client related errors, and should be
// specified with APIClientError.
const (
// AuthenticationFailure occurs when the client is unable
// to obtain an authentication token for the request.
AuthenticationFailure Reason = 100 * (iota + 1)
// JSONError wraps an encoding/json error.
JSONError
// IOError wraps an io/ioutil error.
IOError
// ClientHTTPError wraps a net/http error.
ClientHTTPError
// ServerRequestFailed covers any other failures from the API
// client.
ServerRequestFailed
)
// The following are OCSP related errors, and should be
// specified with OCSPError
const (
// IssuerMismatch ocurs when the certificate in the OCSP signing
// request was not issued by the CA that this responder responds for.
IssuerMismatch Reason = 100 * (iota + 1) // 81XX
// InvalidStatus occurs when the OCSP signing requests includes an
// invalid value for the certificate status.
InvalidStatus
)
// Certificate transparency related errors specified with CTError
const (
// PrecertSubmissionFailed occurs when submitting a precertificate to
// a log server fails
PrecertSubmissionFailed = 100 * (iota + 1)
// CTClientConstructionFailed occurs when the construction of a new
// github.com/google/certificate-transparency client fails.
CTClientConstructionFailed
// PrecertMissingPoison occurs when a precert is passed to SignFromPrecert
// and is missing the CT poison extension.
PrecertMissingPoison
// PrecertInvalidPoison occurs when a precert is passed to SignFromPrecert
// and has a invalid CT poison extension value or the extension is not
// critical.
PrecertInvalidPoison
)
// Certificate persistence related errors specified with CertStoreError
const (
// InsertionFailed occurs when a SQL insert query failes to complete.
InsertionFailed = 100 * (iota + 1)
// RecordNotFound occurs when a SQL query targeting on one unique
// record failes to update the specified row in the table.
RecordNotFound
)
// The error interface implementation, which formats to a JSON object string.
func (e *Error) Error() string {
marshaled, err := json.Marshal(e)
if err != nil {
panic(err)
}
return string(marshaled)
}
// New returns an error that contains an error code and message derived from
// the given category, reason. Currently, to avoid confusion, it is not
// allowed to create an error of category Success
func New(category Category, reason Reason) *Error {
errorCode := int(category) + int(reason)
var msg string
switch category {
case OCSPError:
switch reason {
case ReadFailed:
msg = "No certificate provided"
case IssuerMismatch:
msg = "Certificate not issued by this issuer"
case InvalidStatus:
msg = "Invalid revocation status"
}
case CertificateError:
switch reason {
case Unknown:
msg = "Unknown certificate error"
case ReadFailed:
msg = "Failed to read certificate"
case DecodeFailed:
msg = "Failed to decode certificate"
case ParseFailed:
msg = "Failed to parse certificate"
case SelfSigned:
msg = "Certificate is self signed"
case VerifyFailed:
msg = "Unable to verify certificate"
case BadRequest:
msg = "Invalid certificate request"
case MissingSerial:
msg = "Missing serial number in request"
default:
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category CertificateError.",
reason))
}
case PrivateKeyError:
switch reason {
case Unknown:
msg = "Unknown private key error"
case ReadFailed:
msg = "Failed to read private key"
case DecodeFailed:
msg = "Failed to decode private key"
case ParseFailed:
msg = "Failed to parse private key"
case Encrypted:
msg = "Private key is encrypted."
case NotRSAOrECC:
msg = "Private key algorithm is not RSA or ECC"
case KeyMismatch:
msg = "Private key does not match public key"
case GenerationFailed:
msg = "Failed to new private key"
case Unavailable:
msg = "Private key is unavailable"
default:
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PrivateKeyError.",
reason))
}
case IntermediatesError:
switch reason {
case Unknown:
msg = "Unknown intermediate certificate error"
case ReadFailed:
msg = "Failed to read intermediate certificate"
case DecodeFailed:
msg = "Failed to decode intermediate certificate"
case ParseFailed:
msg = "Failed to parse intermediate certificate"
default:
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category IntermediatesError.",
reason))
}
case RootError:
switch reason {
case Unknown:
msg = "Unknown root certificate error"
case ReadFailed:
msg = "Failed to read root certificate"
case DecodeFailed:
msg = "Failed to decode root certificate"
case ParseFailed:
msg = "Failed to parse root certificate"
default:
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category RootError.",
reason))
}
case PolicyError:
switch reason {
case Unknown:
msg = "Unknown policy error"
case NoKeyUsages:
msg = "Invalid policy: no key usage available"
case InvalidPolicy:
msg = "Invalid or unknown policy"
case InvalidRequest:
msg = "Policy violation request"
case UnknownProfile:
msg = "Unknown policy profile"
case UnmatchedWhitelist:
msg = "Request does not match policy whitelist"
default:
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PolicyError.",
reason))
}
case DialError:
switch reason {
case Unknown:
msg = "Failed to dial remote server"
default:
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category DialError.",
reason))
}
case APIClientError:
switch reason {
case AuthenticationFailure:
msg = "API client authentication failure"
case JSONError:
msg = "API client JSON config error"
case ClientHTTPError:
msg = "API client HTTP error"
case IOError:
msg = "API client IO error"
case ServerRequestFailed:
msg = "API client error: Server request failed"
default:
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category APIClientError.",
reason))
}
case CSRError:
switch reason {
case Unknown:
msg = "CSR parsing failed due to unknown error"
case ReadFailed:
msg = "CSR file read failed"
case ParseFailed:
msg = "CSR Parsing failed"
case DecodeFailed:
msg = "CSR Decode failed"
case BadRequest:
msg = "CSR Bad request"
default:
panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category APIClientError.", reason))
}
case CTError:
switch reason {
case Unknown:
msg = "Certificate transparency parsing failed due to unknown error"
case PrecertSubmissionFailed:
msg = "Certificate transparency precertificate submission failed"
case PrecertMissingPoison:
msg = "Precertificate is missing CT poison extension"
case PrecertInvalidPoison:
msg = "Precertificate contains an invalid CT poison extension"
default:
panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CTError.", reason))
}
case CertStoreError:
switch reason {
case Unknown:
msg = "Certificate store action failed due to unknown error"
default:
panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CertStoreError.", reason))
}
default:
panic(fmt.Sprintf("Unsupported CFSSL error type: %d.",
category))
}
return &Error{ErrorCode: errorCode, Message: msg}
}
// Wrap returns an error that contains the given error and an error code derived from
// the given category, reason and the error. Currently, to avoid confusion, it is not
// allowed to create an error of category Success
func Wrap(category Category, reason Reason, err error) *Error {
errorCode := int(category) + int(reason)
if err == nil {
panic("Wrap needs a supplied error to initialize.")
}
// do not double wrap a error
switch err.(type) {
case *Error:
panic("Unable to wrap a wrapped error.")
}
switch category {
case CertificateError:
// given VerifyFailed , report the status with more detailed status code
// for some certificate errors we care.
if reason == VerifyFailed {
switch errorType := err.(type) {
case x509.CertificateInvalidError:
errorCode += certificateInvalid + int(errorType.Reason)
case x509.UnknownAuthorityError:
errorCode += unknownAuthority
}
}
case PrivateKeyError, IntermediatesError, RootError, PolicyError, DialError,
APIClientError, CSRError, CTError, CertStoreError, OCSPError:
// no-op, just use the error
default:
panic(fmt.Sprintf("Unsupported CFSSL error type: %d.",
category))
}
return &Error{ErrorCode: errorCode, Message: err.Error()}
}

338
vendor/github.com/cloudflare/cfssl/errors/error_test.go generated vendored Normal file
View File

@ -0,0 +1,338 @@
package errors
import (
"crypto/x509"
"encoding/json"
"errors"
"testing"
)
func TestNew(t *testing.T) {
err := New(CertificateError, Unknown)
if err == nil {
t.Fatal("Error creation failed.")
}
if err.ErrorCode != int(CertificateError)+int(Unknown) {
t.Fatal("Error code construction failed.")
}
if err.Message != "Unknown certificate error" {
t.Fatal("Error message construction failed.")
}
code := New(OCSPError, ReadFailed).ErrorCode
if code != 8001 {
t.Fatal("Improper error code")
}
code = New(OCSPError, IssuerMismatch).ErrorCode
if code != 8100 {
t.Fatal("Improper error code")
}
code = New(OCSPError, InvalidStatus).ErrorCode
if code != 8200 {
t.Fatal("Improper error code")
}
code = New(CertificateError, Unknown).ErrorCode
if code != 1000 {
t.Fatal("Improper error code")
}
code = New(CertificateError, ReadFailed).ErrorCode
if code != 1001 {
t.Fatal("Improper error code")
}
code = New(CertificateError, DecodeFailed).ErrorCode
if code != 1002 {
t.Fatal("Improper error code")
}
code = New(CertificateError, ParseFailed).ErrorCode
if code != 1003 {
t.Fatal("Improper error code")
}
code = New(CertificateError, SelfSigned).ErrorCode
if code != 1100 {
t.Fatal("Improper error code")
}
code = New(CertificateError, VerifyFailed).ErrorCode
if code != 1200 {
t.Fatal("Improper error code")
}
code = New(CertificateError, BadRequest).ErrorCode
if code != 1300 {
t.Fatal("Improper error code")
}
code = New(CertificateError, MissingSerial).ErrorCode
if code != 1400 {
t.Fatal("Improper error code")
}
code = New(PrivateKeyError, Unknown).ErrorCode
if code != 2000 {
t.Fatal("Improper error code")
}
code = New(PrivateKeyError, ReadFailed).ErrorCode
if code != 2001 {
t.Fatal("Improper error code")
}
code = New(PrivateKeyError, DecodeFailed).ErrorCode
if code != 2002 {
t.Fatal("Improper error code")
}
code = New(PrivateKeyError, ParseFailed).ErrorCode
if code != 2003 {
t.Fatal("Improper error code")
}
code = New(PrivateKeyError, Encrypted).ErrorCode
if code != 2100 {
t.Fatal("Improper error code")
}
code = New(PrivateKeyError, NotRSAOrECC).ErrorCode
if code != 2200 {
t.Fatal("Improper error code")
}
code = New(PrivateKeyError, KeyMismatch).ErrorCode
if code != 2300 {
t.Fatal("Improper error code")
}
code = New(PrivateKeyError, GenerationFailed).ErrorCode
if code != 2400 {
t.Fatal("Improper error code")
}
code = New(PrivateKeyError, Unavailable).ErrorCode
if code != 2500 {
t.Fatal("Improper error code")
}
code = New(IntermediatesError, Unknown).ErrorCode
if code != 3000 {
t.Fatal("Improper error code")
}
code = New(IntermediatesError, ReadFailed).ErrorCode
if code != 3001 {
t.Fatal("Improper error code")
}
code = New(IntermediatesError, DecodeFailed).ErrorCode
if code != 3002 {
t.Fatal("Improper error code")
}
code = New(IntermediatesError, ParseFailed).ErrorCode
if code != 3003 {
t.Fatal("Improper error code")
}
code = New(RootError, Unknown).ErrorCode
if code != 4000 {
t.Fatal("Improper error code")
}
code = New(RootError, ReadFailed).ErrorCode
if code != 4001 {
t.Fatal("Improper error code")
}
code = New(RootError, DecodeFailed).ErrorCode
if code != 4002 {
t.Fatal("Improper error code")
}
code = New(RootError, ParseFailed).ErrorCode
if code != 4003 {
t.Fatal("Improper error code")
}
code = New(PolicyError, Unknown).ErrorCode
if code != 5000 {
t.Fatal("Improper error code")
}
code = New(PolicyError, NoKeyUsages).ErrorCode
if code != 5100 {
t.Fatal("Improper error code")
}
code = New(PolicyError, InvalidPolicy).ErrorCode
if code != 5200 {
t.Fatal("Improper error code")
}
code = New(PolicyError, InvalidRequest).ErrorCode
if code != 5300 {
t.Fatal("Improper error code")
}
code = New(PolicyError, UnknownProfile).ErrorCode
if code != 5400 {
t.Fatal("Improper error code")
}
code = New(DialError, Unknown).ErrorCode
if code != 6000 {
t.Fatal("Improper error code")
}
code = New(APIClientError, AuthenticationFailure).ErrorCode
if code != 7100 {
t.Fatal("Improper error code")
}
code = New(APIClientError, JSONError).ErrorCode
if code != 7200 {
t.Fatal("Improper error code")
}
code = New(APIClientError, ClientHTTPError).ErrorCode
if code != 7400 {
t.Fatal("Improper error code")
}
code = New(APIClientError, IOError).ErrorCode
if code != 7300 {
t.Fatal("Improper error code")
}
code = New(APIClientError, ServerRequestFailed).ErrorCode
if code != 7500 {
t.Fatal("Improper error code")
}
code = New(CSRError, Unknown).ErrorCode
if code != 9000 {
t.Fatal("Improper error code")
}
code = New(CSRError, ReadFailed).ErrorCode
if code != 9001 {
t.Fatal("Improper error code")
}
code = New(CSRError, DecodeFailed).ErrorCode
if code != 9002 {
t.Fatal("Improper error code")
}
code = New(CSRError, ParseFailed).ErrorCode
if code != 9003 {
t.Fatal("Improper error code")
}
code = New(CSRError, KeyMismatch).ErrorCode
if code != 9300 {
t.Fatal("Improper error code")
}
code = New(CSRError, BadRequest).ErrorCode
if code != 9300 {
t.Fatal("Improper error code")
}
code = New(CTError, Unknown).ErrorCode
if code != 10000 {
t.Fatal("Improper error code")
}
code = New(CTError, PrecertSubmissionFailed).ErrorCode
if code != 10100 {
t.Fatal("Improper error code")
}
}
func TestWrap(t *testing.T) {
msg := "Arbitrary error message"
err := Wrap(CertificateError, Unknown, errors.New(msg))
if err == nil {
t.Fatal("Error creation failed.")
}
if err.ErrorCode != int(CertificateError)+int(Unknown) {
t.Fatal("Error code construction failed.")
}
if err.Message != msg {
t.Fatal("Error message construction failed.")
}
err = Wrap(CertificateError, VerifyFailed, x509.CertificateInvalidError{Reason: x509.Expired})
if err == nil {
t.Fatal("Error creation failed.")
}
if err.ErrorCode != int(CertificateError)+int(VerifyFailed)+certificateInvalid+int(x509.Expired) {
t.Fatal("Error code construction failed.")
}
if err.Message != "x509: certificate has expired or is not yet valid" {
t.Fatal("Error message construction failed.")
}
err = Wrap(CertificateError, VerifyFailed, x509.UnknownAuthorityError{})
if err == nil {
t.Fatal("Error creation failed.")
}
err = Wrap(RootError, Unknown, errors.New(msg))
if err == nil {
t.Fatal("Error creation failed.")
}
if err.ErrorCode != int(RootError)+int(Unknown) {
t.Fatal("Error code construction failed.")
}
if err.Message != msg {
t.Fatal("Error message construction failed.")
}
}
func TestMarshal(t *testing.T) {
msg := "Arbitrary error message"
err := Wrap(CertificateError, Unknown, errors.New(msg))
bytes, _ := json.Marshal(err)
var received Error
json.Unmarshal(bytes, &received)
if received.ErrorCode != int(CertificateError)+int(Unknown) {
t.Fatal("Error code construction failed.")
}
if received.Message != msg {
t.Fatal("Error message construction failed.")
}
}
func TestErrorString(t *testing.T) {
msg := "Arbitrary error message"
err := Wrap(CertificateError, Unknown, errors.New(msg))
str := err.Error()
if str != `{"code":1000,"message":"`+msg+`"}` {
t.Fatal("Incorrect Error():", str)
}
}
func TestHTTP(t *testing.T) {
err := NewMethodNotAllowed("GET")
if err == nil {
t.Fatal("New Mathod Check failed")
}
err = NewBadRequest(errors.New("Bad Request"))
if err == nil {
t.Fatal("New Bad Request Check failed")
}
if err.StatusCode != 400 {
t.Fatal("New Bad Request error code construction failed")
}
err = NewBadRequestString("Bad Request String")
if err == nil {
t.Fatal("New Bad Request String Check failed")
}
if err.StatusCode != 400 {
t.Fatal("New Bad Request String error code construction failed")
}
err = NewBadRequestMissingParameter("Request Missing Parameter")
if err == nil {
t.Fatal("New Bad Request Missing Parameter Check failed")
}
if err.StatusCode != 400 {
t.Fatal("New Bad Request Missing Parameter error code construction failed")
}
err = NewBadRequestUnwantedParameter("Unwanted Parameter Present In Request")
if err == nil {
t.Fatal("New Bad Request Unwanted Parameter Check failed")
}
if err.StatusCode != 400 {
t.Fatal("New Bad Request Unwanted Parameter error code construction failed")
}
}
func TestHTTPErrorString(t *testing.T) {
method := "GET"
err := NewMethodNotAllowed(method)
str := err.Error()
if str != `Method is not allowed:"`+method+`"` {
t.Fatal("Incorrect Error():", str)
}
}

47
vendor/github.com/cloudflare/cfssl/errors/http.go generated vendored Normal file
View File

@ -0,0 +1,47 @@
package errors
import (
"errors"
"net/http"
)
// HTTPError is an augmented error with a HTTP status code.
type HTTPError struct {
StatusCode int
error
}
// Error implements the error interface.
func (e *HTTPError) Error() string {
return e.error.Error()
}
// NewMethodNotAllowed returns an appropriate error in the case that
// an HTTP client uses an invalid method (i.e. a GET in place of a POST)
// on an API endpoint.
func NewMethodNotAllowed(method string) *HTTPError {
return &HTTPError{http.StatusMethodNotAllowed, errors.New(`Method is not allowed:"` + method + `"`)}
}
// NewBadRequest creates a HttpError with the given error and error code 400.
func NewBadRequest(err error) *HTTPError {
return &HTTPError{http.StatusBadRequest, err}
}
// NewBadRequestString returns a HttpError with the supplied message
// and error code 400.
func NewBadRequestString(s string) *HTTPError {
return NewBadRequest(errors.New(s))
}
// NewBadRequestMissingParameter returns a 400 HttpError as a required
// parameter is missing in the HTTP request.
func NewBadRequestMissingParameter(s string) *HTTPError {
return NewBadRequestString(`Missing parameter "` + s + `"`)
}
// NewBadRequestUnwantedParameter returns a 400 HttpError as a unnecessary
// parameter is present in the HTTP request.
func NewBadRequestUnwantedParameter(s string) *HTTPError {
return NewBadRequestString(`Unwanted parameter "` + s + `"`)
}

View File

@ -0,0 +1,42 @@
// Package derhelpers implements common functionality
// on DER encoded data
package derhelpers
import (
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
cferr "github.com/cloudflare/cfssl/errors"
)
// ParsePrivateKeyDER parses a PKCS #1, PKCS #8, or elliptic curve
// DER-encoded private key. The key must not be in PEM format.
func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) {
generalKey, err := x509.ParsePKCS8PrivateKey(keyDER)
if err != nil {
generalKey, err = x509.ParsePKCS1PrivateKey(keyDER)
if err != nil {
generalKey, err = x509.ParseECPrivateKey(keyDER)
if err != nil {
// We don't include the actual error into
// the final error. The reason might be
// we don't want to leak any info about
// the private key.
return nil, cferr.New(cferr.PrivateKeyError,
cferr.ParseFailed)
}
}
}
switch generalKey.(type) {
case *rsa.PrivateKey:
return generalKey.(*rsa.PrivateKey), nil
case *ecdsa.PrivateKey:
return generalKey.(*ecdsa.PrivateKey), nil
}
// should never reach here
return nil, cferr.New(cferr.PrivateKeyError, cferr.ParseFailed)
}

577
vendor/github.com/cloudflare/cfssl/helpers/helpers.go generated vendored Normal file
View File

@ -0,0 +1,577 @@
// Package helpers implements utility functionality common to many
// CFSSL packages.
package helpers
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"os"
"github.com/google/certificate-transparency-go"
cttls "github.com/google/certificate-transparency-go/tls"
ctx509 "github.com/google/certificate-transparency-go/x509"
"golang.org/x/crypto/ocsp"
"strings"
"time"
"github.com/cloudflare/cfssl/crypto/pkcs7"
cferr "github.com/cloudflare/cfssl/errors"
"github.com/cloudflare/cfssl/helpers/derhelpers"
"github.com/cloudflare/cfssl/log"
"golang.org/x/crypto/pkcs12"
)
// OneYear is a time.Duration representing a year's worth of seconds.
const OneYear = 8760 * time.Hour
// OneDay is a time.Duration representing a day's worth of seconds.
const OneDay = 24 * time.Hour
// InclusiveDate returns the time.Time representation of a date - 1
// nanosecond. This allows time.After to be used inclusively.
func InclusiveDate(year int, month time.Month, day int) time.Time {
return time.Date(year, month, day, 0, 0, 0, 0, time.UTC).Add(-1 * time.Nanosecond)
}
// Jul2012 is the July 2012 CAB Forum deadline for when CAs must stop
// issuing certificates valid for more than 5 years.
var Jul2012 = InclusiveDate(2012, time.July, 01)
// Apr2015 is the April 2015 CAB Forum deadline for when CAs must stop
// issuing certificates valid for more than 39 months.
var Apr2015 = InclusiveDate(2015, time.April, 01)
// KeyLength returns the bit size of ECDSA or RSA PublicKey
func KeyLength(key interface{}) int {
if key == nil {
return 0
}
if ecdsaKey, ok := key.(*ecdsa.PublicKey); ok {
return ecdsaKey.Curve.Params().BitSize
} else if rsaKey, ok := key.(*rsa.PublicKey); ok {
return rsaKey.N.BitLen()
}
return 0
}
// ExpiryTime returns the time when the certificate chain is expired.
func ExpiryTime(chain []*x509.Certificate) (notAfter time.Time) {
if len(chain) == 0 {
return
}
notAfter = chain[0].NotAfter
for _, cert := range chain {
if notAfter.After(cert.NotAfter) {
notAfter = cert.NotAfter
}
}
return
}
// MonthsValid returns the number of months for which a certificate is valid.
func MonthsValid(c *x509.Certificate) int {
issued := c.NotBefore
expiry := c.NotAfter
years := (expiry.Year() - issued.Year())
months := years*12 + int(expiry.Month()) - int(issued.Month())
// Round up if valid for less than a full month
if expiry.Day() > issued.Day() {
months++
}
return months
}
// ValidExpiry determines if a certificate is valid for an acceptable
// length of time per the CA/Browser Forum baseline requirements.
// See https://cabforum.org/wp-content/uploads/CAB-Forum-BR-1.3.0.pdf
func ValidExpiry(c *x509.Certificate) bool {
issued := c.NotBefore
var maxMonths int
switch {
case issued.After(Apr2015):
maxMonths = 39
case issued.After(Jul2012):
maxMonths = 60
case issued.Before(Jul2012):
maxMonths = 120
}
if MonthsValid(c) > maxMonths {
return false
}
return true
}
// SignatureString returns the TLS signature string corresponding to
// an X509 signature algorithm.
func SignatureString(alg x509.SignatureAlgorithm) string {
switch alg {
case x509.MD2WithRSA:
return "MD2WithRSA"
case x509.MD5WithRSA:
return "MD5WithRSA"
case x509.SHA1WithRSA:
return "SHA1WithRSA"
case x509.SHA256WithRSA:
return "SHA256WithRSA"
case x509.SHA384WithRSA:
return "SHA384WithRSA"
case x509.SHA512WithRSA:
return "SHA512WithRSA"
case x509.DSAWithSHA1:
return "DSAWithSHA1"
case x509.DSAWithSHA256:
return "DSAWithSHA256"
case x509.ECDSAWithSHA1:
return "ECDSAWithSHA1"
case x509.ECDSAWithSHA256:
return "ECDSAWithSHA256"
case x509.ECDSAWithSHA384:
return "ECDSAWithSHA384"
case x509.ECDSAWithSHA512:
return "ECDSAWithSHA512"
default:
return "Unknown Signature"
}
}
// HashAlgoString returns the hash algorithm name contains in the signature
// method.
func HashAlgoString(alg x509.SignatureAlgorithm) string {
switch alg {
case x509.MD2WithRSA:
return "MD2"
case x509.MD5WithRSA:
return "MD5"
case x509.SHA1WithRSA:
return "SHA1"
case x509.SHA256WithRSA:
return "SHA256"
case x509.SHA384WithRSA:
return "SHA384"
case x509.SHA512WithRSA:
return "SHA512"
case x509.DSAWithSHA1:
return "SHA1"
case x509.DSAWithSHA256:
return "SHA256"
case x509.ECDSAWithSHA1:
return "SHA1"
case x509.ECDSAWithSHA256:
return "SHA256"
case x509.ECDSAWithSHA384:
return "SHA384"
case x509.ECDSAWithSHA512:
return "SHA512"
default:
return "Unknown Hash Algorithm"
}
}
// EncodeCertificatesPEM encodes a number of x509 certificates to PEM
func EncodeCertificatesPEM(certs []*x509.Certificate) []byte {
var buffer bytes.Buffer
for _, cert := range certs {
pem.Encode(&buffer, &pem.Block{
Type: "CERTIFICATE",
Bytes: cert.Raw,
})
}
return buffer.Bytes()
}
// EncodeCertificatePEM encodes a single x509 certificates to PEM
func EncodeCertificatePEM(cert *x509.Certificate) []byte {
return EncodeCertificatesPEM([]*x509.Certificate{cert})
}
// ParseCertificatesPEM parses a sequence of PEM-encoded certificate and returns them,
// can handle PEM encoded PKCS #7 structures.
func ParseCertificatesPEM(certsPEM []byte) ([]*x509.Certificate, error) {
var certs []*x509.Certificate
var err error
certsPEM = bytes.TrimSpace(certsPEM)
for len(certsPEM) > 0 {
var cert []*x509.Certificate
cert, certsPEM, err = ParseOneCertificateFromPEM(certsPEM)
if err != nil {
return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed)
} else if cert == nil {
break
}
certs = append(certs, cert...)
}
if len(certsPEM) > 0 {
return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
}
return certs, nil
}
// ParseCertificatesDER parses a DER encoding of a certificate object and possibly private key,
// either PKCS #7, PKCS #12, or raw x509.
func ParseCertificatesDER(certsDER []byte, password string) (certs []*x509.Certificate, key crypto.Signer, err error) {
certsDER = bytes.TrimSpace(certsDER)
pkcs7data, err := pkcs7.ParsePKCS7(certsDER)
if err != nil {
var pkcs12data interface{}
certs = make([]*x509.Certificate, 1)
pkcs12data, certs[0], err = pkcs12.Decode(certsDER, password)
if err != nil {
certs, err = x509.ParseCertificates(certsDER)
if err != nil {
return nil, nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
}
} else {
key = pkcs12data.(crypto.Signer)
}
} else {
if pkcs7data.ContentInfo != "SignedData" {
return nil, nil, cferr.Wrap(cferr.CertificateError, cferr.DecodeFailed, errors.New("can only extract certificates from signed data content info"))
}
certs = pkcs7data.Content.SignedData.Certificates
}
if certs == nil {
return nil, key, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
}
return certs, key, nil
}
// ParseSelfSignedCertificatePEM parses a PEM-encoded certificate and check if it is self-signed.
func ParseSelfSignedCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
cert, err := ParseCertificatePEM(certPEM)
if err != nil {
return nil, err
}
if err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.VerifyFailed, err)
}
return cert, nil
}
// ParseCertificatePEM parses and returns a PEM-encoded certificate,
// can handle PEM encoded PKCS #7 structures.
func ParseCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
certPEM = bytes.TrimSpace(certPEM)
cert, rest, err := ParseOneCertificateFromPEM(certPEM)
if err != nil {
// Log the actual parsing error but throw a default parse error message.
log.Debugf("Certificate parsing error: %v", err)
return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed)
} else if cert == nil {
return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
} else if len(rest) > 0 {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PEM file should contain only one object"))
} else if len(cert) > 1 {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PKCS7 object in the PEM file should contain only one certificate"))
}
return cert[0], nil
}
// ParseOneCertificateFromPEM attempts to parse one PEM encoded certificate object,
// either a raw x509 certificate or a PKCS #7 structure possibly containing
// multiple certificates, from the top of certsPEM, which itself may
// contain multiple PEM encoded certificate objects.
func ParseOneCertificateFromPEM(certsPEM []byte) ([]*x509.Certificate, []byte, error) {
block, rest := pem.Decode(certsPEM)
if block == nil {
return nil, rest, nil
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
pkcs7data, err := pkcs7.ParsePKCS7(block.Bytes)
if err != nil {
return nil, rest, err
}
if pkcs7data.ContentInfo != "SignedData" {
return nil, rest, errors.New("only PKCS #7 Signed Data Content Info supported for certificate parsing")
}
certs := pkcs7data.Content.SignedData.Certificates
if certs == nil {
return nil, rest, errors.New("PKCS #7 structure contains no certificates")
}
return certs, rest, nil
}
var certs = []*x509.Certificate{cert}
return certs, rest, nil
}
// LoadPEMCertPool loads a pool of PEM certificates from file.
func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) {
if certsFile == "" {
return nil, nil
}
pemCerts, err := ioutil.ReadFile(certsFile)
if err != nil {
return nil, err
}
return PEMToCertPool(pemCerts)
}
// PEMToCertPool concerts PEM certificates to a CertPool.
func PEMToCertPool(pemCerts []byte) (*x509.CertPool, error) {
if len(pemCerts) == 0 {
return nil, nil
}
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(pemCerts) {
return nil, errors.New("failed to load cert pool")
}
return certPool, nil
}
// ParsePrivateKeyPEM parses and returns a PEM-encoded private
// key. The private key may be either an unencrypted PKCS#8, PKCS#1,
// or elliptic private key.
func ParsePrivateKeyPEM(keyPEM []byte) (key crypto.Signer, err error) {
return ParsePrivateKeyPEMWithPassword(keyPEM, nil)
}
// ParsePrivateKeyPEMWithPassword parses and returns a PEM-encoded private
// key. The private key may be a potentially encrypted PKCS#8, PKCS#1,
// or elliptic private key.
func ParsePrivateKeyPEMWithPassword(keyPEM []byte, password []byte) (key crypto.Signer, err error) {
keyDER, err := GetKeyDERFromPEM(keyPEM, password)
if err != nil {
return nil, err
}
return derhelpers.ParsePrivateKeyDER(keyDER)
}
// GetKeyDERFromPEM parses a PEM-encoded private key and returns DER-format key bytes.
func GetKeyDERFromPEM(in []byte, password []byte) ([]byte, error) {
keyDER, _ := pem.Decode(in)
if keyDER != nil {
if procType, ok := keyDER.Headers["Proc-Type"]; ok {
if strings.Contains(procType, "ENCRYPTED") {
if password != nil {
return x509.DecryptPEMBlock(keyDER, password)
}
return nil, cferr.New(cferr.PrivateKeyError, cferr.Encrypted)
}
}
return keyDER.Bytes, nil
}
return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed)
}
// ParseCSR parses a PEM- or DER-encoded PKCS #10 certificate signing request.
func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) {
in = bytes.TrimSpace(in)
p, rest := pem.Decode(in)
if p != nil {
if p.Type != "NEW CERTIFICATE REQUEST" && p.Type != "CERTIFICATE REQUEST" {
return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest)
}
csr, err = x509.ParseCertificateRequest(p.Bytes)
} else {
csr, err = x509.ParseCertificateRequest(in)
}
if err != nil {
return nil, rest, err
}
err = csr.CheckSignature()
if err != nil {
return nil, rest, err
}
return csr, rest, nil
}
// ParseCSRPEM parses a PEM-encoded certificate signing request.
// It does not check the signature. This is useful for dumping data from a CSR
// locally.
func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
block, _ := pem.Decode([]byte(csrPEM))
if block == nil {
return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed)
}
csrObject, err := x509.ParseCertificateRequest(block.Bytes)
if err != nil {
return nil, err
}
return csrObject, nil
}
// SignerAlgo returns an X.509 signature algorithm from a crypto.Signer.
func SignerAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
switch pub := priv.Public().(type) {
case *rsa.PublicKey:
bitLength := pub.N.BitLen()
switch {
case bitLength >= 4096:
return x509.SHA512WithRSA
case bitLength >= 3072:
return x509.SHA384WithRSA
case bitLength >= 2048:
return x509.SHA256WithRSA
default:
return x509.SHA1WithRSA
}
case *ecdsa.PublicKey:
switch pub.Curve {
case elliptic.P521():
return x509.ECDSAWithSHA512
case elliptic.P384():
return x509.ECDSAWithSHA384
case elliptic.P256():
return x509.ECDSAWithSHA256
default:
return x509.ECDSAWithSHA1
}
default:
return x509.UnknownSignatureAlgorithm
}
}
// LoadClientCertificate load key/certificate from pem files
func LoadClientCertificate(certFile string, keyFile string) (*tls.Certificate, error) {
if certFile != "" && keyFile != "" {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Critical("Unable to read client certificate from file: %s or key from file: %s", certFile, keyFile)
return nil, err
}
log.Debug("Client certificate loaded ")
return &cert, nil
}
return nil, nil
}
// CreateTLSConfig creates a tls.Config object from certs and roots
func CreateTLSConfig(remoteCAs *x509.CertPool, cert *tls.Certificate) *tls.Config {
var certs []tls.Certificate
if cert != nil {
certs = []tls.Certificate{*cert}
}
return &tls.Config{
Certificates: certs,
RootCAs: remoteCAs,
}
}
// SerializeSCTList serializes a list of SCTs.
func SerializeSCTList(sctList []ct.SignedCertificateTimestamp) ([]byte, error) {
list := ctx509.SignedCertificateTimestampList{}
for _, sct := range sctList {
sctBytes, err := cttls.Marshal(sct)
if err != nil {
return nil, err
}
list.SCTList = append(list.SCTList, ctx509.SerializedSCT{Val: sctBytes})
}
return cttls.Marshal(list)
}
// DeserializeSCTList deserializes a list of SCTs.
func DeserializeSCTList(serializedSCTList []byte) ([]ct.SignedCertificateTimestamp, error) {
var sctList ctx509.SignedCertificateTimestampList
rest, err := cttls.Unmarshal(serializedSCTList, &sctList)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("serialized SCT list contained trailing garbage"))
}
list := make([]ct.SignedCertificateTimestamp, len(sctList.SCTList))
for i, serializedSCT := range sctList.SCTList {
var sct ct.SignedCertificateTimestamp
rest, err := cttls.Unmarshal(serializedSCT.Val, &sct)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("serialized SCT contained trailing garbage"))
}
list[i] = sct
}
return list, nil
}
// SCTListFromOCSPResponse extracts the SCTList from an ocsp.Response,
// returning an empty list if the SCT extension was not found or could not be
// unmarshalled.
func SCTListFromOCSPResponse(response *ocsp.Response) ([]ct.SignedCertificateTimestamp, error) {
// This loop finds the SCTListExtension in the OCSP response.
var SCTListExtension, ext pkix.Extension
for _, ext = range response.Extensions {
// sctExtOid is the ObjectIdentifier of a Signed Certificate Timestamp.
sctExtOid := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5}
if ext.Id.Equal(sctExtOid) {
SCTListExtension = ext
break
}
}
// This code block extracts the sctList from the SCT extension.
var sctList []ct.SignedCertificateTimestamp
var err error
if numBytes := len(SCTListExtension.Value); numBytes != 0 {
var serializedSCTList []byte
rest := make([]byte, numBytes)
copy(rest, SCTListExtension.Value)
for len(rest) != 0 {
rest, err = asn1.Unmarshal(rest, &serializedSCTList)
if err != nil {
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
}
}
sctList, err = DeserializeSCTList(serializedSCTList)
}
return sctList, err
}
// ReadBytes reads a []byte either from a file or an environment variable.
// If valFile has a prefix of 'env:', the []byte is read from the environment
// using the subsequent name. If the prefix is 'file:' the []byte is read from
// the subsequent file. If no prefix is provided, valFile is assumed to be a
// file path.
func ReadBytes(valFile string) ([]byte, error) {
switch splitVal := strings.SplitN(valFile, ":", 2); len(splitVal) {
case 1:
return ioutil.ReadFile(valFile)
case 2:
switch splitVal[0] {
case "env":
return []byte(os.Getenv(splitVal[1])), nil
case "file":
return ioutil.ReadFile(splitVal[1])
default:
return nil, fmt.Errorf("unknown prefix: %s", splitVal[0])
}
default:
return nil, fmt.Errorf("multiple prefixes: %s",
strings.Join(splitVal[:len(splitVal)-1], ", "))
}
}

View File

@ -0,0 +1,629 @@
package helpers
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"io/ioutil"
"math"
"testing"
"time"
"golang.org/x/crypto/ocsp"
"github.com/google/certificate-transparency-go"
)
const (
testCertFile = "testdata/cert.pem"
testCertDERFile = "testdata/cert.der"
testBundleFile = "testdata/bundle.pem"
testExtraWSCertFile = "testdata/cert_with_whitespace.pem"
testExtraWSBundleFile = "testdata/bundle_with_whitespace.pem"
testMessedUpBundleFile = "testdata/messed_up_bundle.pem"
testMessedUpCertFile = "testdata/messedupcert.pem"
testEmptyCertFile = "testdata/emptycert.pem"
testPrivateRSAKey = "testdata/priv_rsa_key.pem"
testPrivateECDSAKey = "testdata/private_ecdsa_key.pem"
testUnsupportedECDSAKey = "testdata/secp256k1-key.pem"
testMessedUpPrivateKey = "testdata/messed_up_priv_key.pem"
testEncryptedPrivateKey = "testdata/enc_priv_key.pem"
testEmptyPem = "testdata/empty.pem"
testNoHeaderCert = "testdata/noheadercert.pem"
testSinglePKCS7 = "testdata/cert_pkcs7.pem" // openssl crl2pkcs7 -nocrl -out cert_pkcs7.pem -in cert.pem
testEmptyPKCS7DER = "testdata/empty_pkcs7.der" // openssl crl2pkcs7 -nocrl -out empty_pkcs7.der -outform der
testEmptyPKCS7PEM = "testdata/empty_pkcs7.pem" // openssl crl2pkcs7 -nocrl -out empty_pkcs7.pem -outform pem
testMultiplePKCS7 = "testdata/bundle_pkcs7.pem"
testPKCS12EmptyPswd = "testdata/emptypasswordpkcs12.p12"
testPKCS12Passwordispassword = "testdata/passwordpkcs12.p12"
testPKCS12MultipleCerts = "testdata/multiplecerts.p12"
testCSRPEM = "testdata/test.csr.pem"
testCSRPEMBad = "testdata/test.bad.csr.pem"
)
func TestParseCertificatesDER(t *testing.T) {
var password = []string{"password", "", ""}
for i, testFile := range []string{testPKCS12Passwordispassword, testPKCS12EmptyPswd, testCertDERFile} {
testDER, err := ioutil.ReadFile(testFile)
if err != nil {
t.Fatal(err)
}
if _, _, err := ParseCertificatesDER(testDER, password[i]); err != nil {
t.Fatal(err)
}
// Incorrect Password for PKCS12 formatted files
if _, _, err := ParseCertificatesDER(testDER, "incorrectpassword"); err == nil && i != 2 {
t.Fatal(err)
}
}
testDER, err := ioutil.ReadFile(testEmptyPKCS7DER)
if err != nil {
t.Fatal(err)
}
// PKCS7 with no certificates
if _, _, err := ParseCertificatesDER(testDER, ""); err == nil {
t.Fatal(err)
}
}
func TestKeyLength(t *testing.T) {
expNil := 0
recNil := KeyLength(nil)
if expNil != recNil {
t.Fatal("KeyLength on nil did not return 0")
}
expNonsense := 0
inNonsense := "string?"
outNonsense := KeyLength(inNonsense)
if expNonsense != outNonsense {
t.Fatal("KeyLength malfunctioning on nonsense input")
}
//test the ecdsa branch
ecdsaPriv, _ := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
ecdsaIn, _ := ecdsaPriv.Public().(*ecdsa.PublicKey)
expEcdsa := ecdsaIn.Curve.Params().BitSize
outEcdsa := KeyLength(ecdsaIn)
if expEcdsa != outEcdsa {
t.Fatal("KeyLength malfunctioning on ecdsa input")
}
//test the rsa branch
rsaPriv, _ := rsa.GenerateKey(rand.Reader, 256)
rsaIn, _ := rsaPriv.Public().(*rsa.PublicKey)
expRsa := rsaIn.N.BitLen()
outRsa := KeyLength(rsaIn)
if expRsa != outRsa {
t.Fatal("KeyLength malfunctioning on rsa input")
}
}
func TestExpiryTime(t *testing.T) {
// nil case
var expNil time.Time
inNil := []*x509.Certificate{}
outNil := ExpiryTime(inNil)
if expNil != outNil {
t.Fatal("Expiry time is malfunctioning on empty input")
}
//read a pem file and use that expiry date
bytes, _ := ioutil.ReadFile(testBundleFile)
certs, err := ParseCertificatesPEM(bytes)
if err != nil {
t.Fatalf("%v", err)
}
expected := time.Date(2014, time.April, 15, 0, 0, 0, 0, time.UTC)
out := ExpiryTime(certs)
if out != expected {
t.Fatalf("Expected %v, got %v", expected, out)
}
}
func TestMonthsValid(t *testing.T) {
var cert = &x509.Certificate{
NotBefore: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC),
NotAfter: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC),
}
if MonthsValid(cert) != 0 {
t.Fail()
}
cert.NotAfter = time.Date(2016, time.April, 01, 0, 0, 0, 0, time.UTC)
if MonthsValid(cert) != 12 {
t.Fail()
}
// extra days should be rounded up to 1 month
cert.NotAfter = time.Date(2016, time.April, 02, 0, 0, 0, 0, time.UTC)
if MonthsValid(cert) != 13 {
t.Fail()
}
}
func TestHasValidExpiry(t *testing.T) {
// Issue period > April 1, 2015
var cert = &x509.Certificate{
NotBefore: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC),
NotAfter: time.Date(2016, time.April, 01, 0, 0, 0, 0, time.UTC),
}
if !ValidExpiry(cert) {
t.Fail()
}
cert.NotAfter = time.Date(2019, time.April, 01, 01, 0, 0, 0, time.UTC)
if ValidExpiry(cert) {
t.Fail()
}
// Issue period < July 1, 2012
cert.NotBefore = time.Date(2009, time.March, 01, 0, 0, 0, 0, time.UTC)
if ValidExpiry(cert) {
t.Fail()
}
// Issue period July 1, 2012 - April 1, 2015
cert.NotBefore = time.Date(2012, time.July, 01, 0, 0, 0, 0, time.UTC)
cert.NotAfter = time.Date(2017, time.July, 01, 0, 0, 0, 0, time.UTC)
if !ValidExpiry(cert) {
t.Fail()
}
}
func TestHashAlgoString(t *testing.T) {
if HashAlgoString(x509.MD2WithRSA) != "MD2" {
t.Fatal("standin")
}
if HashAlgoString(x509.MD5WithRSA) != "MD5" {
t.Fatal("standin")
}
if HashAlgoString(x509.SHA1WithRSA) != "SHA1" {
t.Fatal("standin")
}
if HashAlgoString(x509.SHA256WithRSA) != "SHA256" {
t.Fatal("standin")
}
if HashAlgoString(x509.SHA384WithRSA) != "SHA384" {
t.Fatal("standin")
}
if HashAlgoString(x509.SHA512WithRSA) != "SHA512" {
t.Fatal("standin")
}
if HashAlgoString(x509.DSAWithSHA1) != "SHA1" {
t.Fatal("standin")
}
if HashAlgoString(x509.DSAWithSHA256) != "SHA256" {
t.Fatal("standin")
}
if HashAlgoString(x509.ECDSAWithSHA1) != "SHA1" {
t.Fatal("standin")
}
if HashAlgoString(x509.ECDSAWithSHA256) != "SHA256" {
t.Fatal("standin")
}
if HashAlgoString(x509.ECDSAWithSHA384) != "SHA384" {
t.Fatal("standin")
}
if HashAlgoString(x509.ECDSAWithSHA512) != "SHA512" {
t.Fatal("standin")
}
if HashAlgoString(math.MaxInt32) != "Unknown Hash Algorithm" {
t.Fatal("standin")
}
}
func TestSignatureString(t *testing.T) {
if SignatureString(x509.MD2WithRSA) != "MD2WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.MD5WithRSA) != "MD5WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.SHA1WithRSA) != "SHA1WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.SHA256WithRSA) != "SHA256WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.SHA384WithRSA) != "SHA384WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.SHA512WithRSA) != "SHA512WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.DSAWithSHA1) != "DSAWithSHA1" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.DSAWithSHA256) != "DSAWithSHA256" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.ECDSAWithSHA1) != "ECDSAWithSHA1" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.ECDSAWithSHA256) != "ECDSAWithSHA256" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.ECDSAWithSHA384) != "ECDSAWithSHA384" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.ECDSAWithSHA512) != "ECDSAWithSHA512" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(math.MaxInt32) != "Unknown Signature" {
t.Fatal("Signature String functioning improperly")
}
}
func TestParseCertificatePEM(t *testing.T) {
for _, testFile := range []string{testCertFile, testExtraWSCertFile, testSinglePKCS7} {
certPEM, err := ioutil.ReadFile(testFile)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCertificatePEM(certPEM); err != nil {
t.Log(testFile)
t.Fatal(err)
}
}
for _, testFile := range []string{testBundleFile, testMessedUpCertFile, testEmptyPKCS7PEM, testEmptyCertFile, testMultiplePKCS7} {
certPEM, err := ioutil.ReadFile(testFile)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCertificatePEM(certPEM); err == nil {
t.Fatal("Incorrect cert failed to raise error")
}
}
}
func TestParseCertificatesPEM(t *testing.T) {
// expected cases
for _, testFile := range []string{testBundleFile, testExtraWSBundleFile, testSinglePKCS7, testMultiplePKCS7} {
bundlePEM, err := ioutil.ReadFile(testFile)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCertificatesPEM(bundlePEM); err != nil {
t.Log(testFile)
t.Fatal(err)
}
}
// test failure cases
// few lines deleted, then headers removed
for _, testFile := range []string{testMessedUpBundleFile, testEmptyPKCS7PEM, testNoHeaderCert} {
bundlePEM, err := ioutil.ReadFile(testFile)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCertificatesPEM(bundlePEM); err == nil {
t.Fatal("Incorrectly-formatted file failed to produce an error")
}
}
}
func TestSelfSignedCertificatePEM(t *testing.T) {
testPEM, _ := ioutil.ReadFile(testCertFile)
_, err := ParseSelfSignedCertificatePEM(testPEM)
if err != nil {
t.Fatalf("%v", err)
}
// a few lines deleted from the pem file
wrongPEM, _ := ioutil.ReadFile(testMessedUpCertFile)
_, err2 := ParseSelfSignedCertificatePEM(wrongPEM)
if err2 == nil {
t.Fatal("Improper pem file failed to raise an error")
}
// alter the signature of a valid certificate
blk, _ := pem.Decode(testPEM)
blk.Bytes[len(blk.Bytes)-10]++ // some hacking to get to the sig
alteredBytes := pem.EncodeToMemory(blk)
_, err = ParseSelfSignedCertificatePEM(alteredBytes)
if err == nil {
t.Fatal("Incorrect cert failed to produce an error")
}
}
func TestParsePrivateKeyPEM(t *testing.T) {
// expected cases
testRSAPEM, _ := ioutil.ReadFile(testPrivateRSAKey)
_, err := ParsePrivateKeyPEM(testRSAPEM)
if err != nil {
t.Fatal(err)
}
testECDSAPEM, _ := ioutil.ReadFile(testPrivateECDSAKey)
_, err = ParsePrivateKeyPEM(testECDSAPEM)
if err != nil {
t.Fatal(err)
}
// error cases
errCases := []string{
testMessedUpPrivateKey, // a few lines deleted
testEmptyPem, // empty file
testEncryptedPrivateKey, // encrypted key
testUnsupportedECDSAKey, // ECDSA curve not currently supported by Go standard library
}
for _, fname := range errCases {
testPEM, _ := ioutil.ReadFile(fname)
_, err = ParsePrivateKeyPEM(testPEM)
if err == nil {
t.Fatal("Incorrect private key failed to produce an error")
}
}
}
// Imported from signers/local/testdata/
const ecdsaTestCSR = "testdata/ecdsa256.csr"
func TestParseCSRPEM(t *testing.T) {
in, err := ioutil.ReadFile(ecdsaTestCSR)
if err != nil {
t.Fatalf("%v", err)
}
_, _, err = ParseCSR(in)
if err != nil {
t.Fatalf("%v", err)
}
in[12]++
_, _, err = ParseCSR(in)
if err == nil {
t.Fatalf("Expected an invalid CSR.")
}
in[12]--
}
func TestParseCSRPEMMore(t *testing.T) {
csrPEM, err := ioutil.ReadFile(testCSRPEM)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCSRPEM(csrPEM); err != nil {
t.Fatal(err)
}
csrPEM, err = ioutil.ReadFile(testCSRPEMBad)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCSRPEM(csrPEM); err == nil {
t.Fatal(err)
}
if _, err := ParseCSRPEM([]byte("not even pem")); err == nil {
t.Fatal("Expected an invalid CSR.")
}
}
// Imported from signers/local/testdata/
const rsaOldTestCSR = "testdata/rsa-old.csr"
func TestParseOldCSR(t *testing.T) {
in, err := ioutil.ReadFile(rsaOldTestCSR)
if err != nil {
t.Fatalf("%v", err)
}
_, _, err = ParseCSR(in)
if err != nil {
t.Fatalf("%v", err)
}
}
// Imported from signers/local/testdata/
const clientCertFile = "testdata/ca.pem"
const clientKeyFile = "testdata/ca_key.pem"
func TestClientCertParams(t *testing.T) {
_, err := LoadClientCertificate(testCertFile, testPrivateRSAKey)
if err == nil {
t.Fatal("Unmatched cert/key should generate error")
}
cert, err := LoadClientCertificate("", "")
if err != nil || cert != nil {
t.Fatal("Certificate atempted to loaded with missing key and cert")
}
cert, err = LoadClientCertificate(clientCertFile, "")
if err != nil || cert != nil {
t.Fatal("Certificate atempted to loaded with missing key")
}
cert, err = LoadClientCertificate("", clientKeyFile)
if err != nil || cert != nil {
t.Fatal("Certificate atempted to loaded with missing cert")
}
cert, err = LoadClientCertificate(clientCertFile, clientKeyFile)
if err != nil {
t.Fatal(err)
}
if cert == nil {
t.Fatal("cert not created")
}
}
func TestLoadPEMCertPool(t *testing.T) {
certPool, err := PEMToCertPool([]byte{})
if certPool != nil || err != nil {
t.Fatal("Empty file name should not generate error or a cert pool")
}
in, err := ioutil.ReadFile(testEmptyPem)
if err != nil {
t.Fatalf("%v", err)
}
certPool, err = PEMToCertPool(in)
if certPool != nil {
t.Fatal("Empty file should not generate a cert pool")
} else if err == nil {
t.Fatal("Expected error for empty file")
}
in, err = ioutil.ReadFile(testEmptyCertFile)
if err != nil {
t.Fatalf("%v", err)
}
certPool, err = PEMToCertPool(in)
if certPool != nil {
t.Fatal("Empty cert should not generate a cert pool")
} else if err == nil {
t.Fatal("Expected error for empty cert")
}
in, err = ioutil.ReadFile(clientCertFile)
if err != nil {
t.Fatalf("%v", err)
}
certPool, err = PEMToCertPool(in)
if err != nil {
t.Fatalf("%v", err)
} else if certPool == nil {
t.Fatal("cert pool not created")
}
}
// sctEquals returns true if all fields of both SCTs are equivalent.
func sctEquals(sctA, sctB ct.SignedCertificateTimestamp) bool {
if sctA.SCTVersion == sctB.SCTVersion &&
sctA.LogID == sctB.LogID &&
sctA.Timestamp == sctB.Timestamp &&
bytes.Equal(sctA.Extensions, sctB.Extensions) &&
sctA.Signature.Algorithm == sctB.Signature.Algorithm &&
bytes.Equal(sctA.Signature.Signature, sctA.Signature.Signature) {
return true
}
return false
}
// NOTE: TestDeserializeSCTList tests both DeserializeSCTList and
// SerializeSCTList.
func TestDeserializeSCTList(t *testing.T) {
// Here we make sure that empty SCT lists return an error
emptyLists := [][]byte{nil, {}}
for _, emptyList := range emptyLists {
_, err := DeserializeSCTList(emptyList)
if err == nil {
t.Fatalf("DeserializeSCTList(%v) should raise an error\n", emptyList)
}
}
// Here we make sure that an SCT list with a zero SCT is deserialized
// correctly
var zeroSCT ct.SignedCertificateTimestamp
serializedSCT, err := SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT})
if err != nil {
t.Fatal(err)
}
deserializedSCTList, err := DeserializeSCTList(serializedSCT)
if err != nil {
t.Fatal(err)
}
if !sctEquals(zeroSCT, (deserializedSCTList)[0]) {
t.Fatal("SCTs don't match")
}
// Here we verify that an error is raised when the SCT list length
// field is greater than its actual length
serializedSCT, err = SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT})
if err != nil {
t.Fatal(err)
}
serializedSCT[0] = 15
_, err = DeserializeSCTList(serializedSCT)
if err == nil {
t.Fatalf("DeserializeSCTList should raise an error when " +
"the SCT list length field and the list length don't match\n")
}
// Here we verify that an error is raised when the SCT list length
// field is less than its actual length
serializedSCT[0] = 0
serializedSCT[1] = 0
_, err = DeserializeSCTList(serializedSCT)
if err == nil {
t.Fatalf("DeserializeSCTList should raise an error when " +
"the SCT list length field and the list length don't match\n")
}
// Here we verify that an error is raised when the SCT length field is
// greater than its actual length
serializedSCT[0] = 0
serializedSCT[1] = 49
serializedSCT[2] = 1
_, err = DeserializeSCTList(serializedSCT)
if err == nil {
t.Fatalf("DeserializeSCTList should raise an error when " +
"the SCT length field and the SCT length don't match\n")
}
// Here we verify that an error is raised when the SCT length field is
// less than its actual length
serializedSCT[2] = 0
serializedSCT[3] = 0
_, err = DeserializeSCTList(serializedSCT)
if err == nil {
t.Fatalf("DeserializeSCTList should raise an error when " +
"the SCT length field and the SCT length don't match\n")
}
}
func TestSCTListFromOCSPResponse(t *testing.T) {
var response ocsp.Response
lst, err := SCTListFromOCSPResponse(&response)
if err != nil {
t.Fatal(err)
}
if len(lst) != 0 {
t.Fatal("SCTListFromOCSPResponse should return an empty SCT list for an empty extension")
}
var zeroSCT ct.SignedCertificateTimestamp
serializedSCTList, err := SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT})
if err != nil {
t.Fatal("failed to serialize SCT list")
}
serializedSCTList, err = asn1.Marshal(serializedSCTList)
if err != nil {
t.Fatal("failed to serialize SCT list")
}
// The value of Id below is the object identifier of the OCSP Stapling
// SCT extension (see section 3.3. of RFC 6962).
response.Extensions = []pkix.Extension{{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5},
Critical: false,
Value: serializedSCTList,
}}
lst, err = SCTListFromOCSPResponse(&response)
if err != nil {
t.Fatal(err)
}
if !sctEquals(zeroSCT, lst[0]) {
t.Fatal("SCTs don't match")
}
}

View File

@ -0,0 +1,53 @@
-----BEGIN CERTIFICATE-----
MIIEczCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG
EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp
bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv
cm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAw
MDAwWhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs
b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT
DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNs
b3VkZmxhcmUtaW50ZXIuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIVkjNJGw
f3F0XWJH7yQSVtxuoBidi5JNsQ7FhxEQcZEl3b+/1iF60TBY2Yi6KwJuA6nIE73P
IXGyfNhThw4D8CiZbackQ/ufgz2DyvxyWFDPzLr7TXeM/0wSp/imoxWeo4GIMIGF
MA4GA1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRB
+YoiUjIm34/wBwHdJGE4Wufs/DAfBgNVHSMEGDAWgBTXXUgpaSwO9HOrQBxGqOOS
FHsHEDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0B
AQsDggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJd
FI1UjL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHF
A145JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j
4WCv5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7c
WWOay6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvT
br6+bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs
369/Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2Ygh
PsypDo33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpw
EPVqTR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS
/mg1t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH
0thnUGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuT
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEkDCCA/ugAwIBAgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT
AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv
MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG
A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAw
MDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE
CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j
b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL
AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng
xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW
RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu
u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU
mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0
APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys
sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT
7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7
STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow
TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND
DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDAS
BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH
EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRj
bG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/
fWznVvOEFAAYZByPFx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9
fC7vf45B2zCX0OW51QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnch
DaMsXjQQTJu0iuG3qKEuCmUwOmc=
-----END CERTIFICATE-----

View File

@ -0,0 +1,52 @@
-----BEGIN PKCS7-----
MIIJOAYJKoZIhvcNAQcCoIIJKTCCCSUCAQExADALBgkqhkiG9w0BBwGgggkLMIIE
czCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQGEwJV
UzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVl
cmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5p
YTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAwMDAw
WhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNsb3Vk
RmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcTDVNh
biBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNsb3Vk
ZmxhcmUtaW50ZXIuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIVkjNJGwf3F0
XWJH7yQSVtxuoBidi5JNsQ7FhxEQcZEl3b+/1iF60TBY2Yi6KwJuA6nIE73PIXGy
fNhThw4D8CiZbackQ/ufgz2DyvxyWFDPzLr7TXeM/0wSp/imoxWeo4GIMIGFMA4G
A1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRB+Yoi
UjIm34/wBwHdJGE4Wufs/DAfBgNVHSMEGDAWgBTXXUgpaSwO9HOrQBxGqOOSFHsH
EDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsD
ggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJdFI1U
jL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHFA145
JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j4WCv
5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7cWWOa
y6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvTbr6+
bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs369/
Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2YghPsyp
Do33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpwEPVq
TR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS/mg1
t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH0thn
UGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuTMIIEkDCCA/ugAwIB
AgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYTAlVTMRMwEQYDVQQI
DApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKDApD
bG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQGA1UEAwwNQ0ZTU0xf
VEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAwMDBaMIGMMQswCQYD
VQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBF
bmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2Fs
aWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHLAlI+xwnPhWgzj2Ve
vD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0NgxxwQ2rC08fJtCnij
lGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeWRbWuLH5nEMdyk9Np
etS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fuu6pgMtHKvl4GGH0y
vb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREUmlcY5EvpR141KXbZ
qiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0APJx1VNSSH6XoDpU
ETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsyssWBEN+CxK19xyPum
r21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT7r3mzlBTYl3poU26
q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7STOs8wuTu3huSnan
/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuowTmmHlb8KIMa9mOvc
uGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VNDDL3J/vSVlFeqLt2r
eAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAG
AQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsHEDAfBgNVHSMEGDAW
gBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWlu
dGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/fWznVvOEFAAYZByP
Fx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9fC7vf45B2zCX0OW5
1QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnchDaMsXjQQTJu0iuG3
qKEuCmUwOmehADEA
-----END PKCS7-----

View File

@ -0,0 +1,56 @@
-----BEGIN CERTIFICATE-----
MIIEczCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG
EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp
bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv
cm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAw
MDAwWhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs
b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT
DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNs
b3VkZmxhcmUtaW50ZXIuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIVkjNJGw
f3F0XWJH7yQSVtxuoBidi5JNsQ7FhxEQcZEl3b+/1iF60TBY2Yi6KwJuA6nIE73P
IXGyfNhThw4D8CiZbackQ/ufgz2DyvxyWFDPzLr7TXeM/0wSp/imoxWeo4GIMIGF
MA4GA1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRB
+YoiUjIm34/wBwHdJGE4Wufs/DAfBgNVHSMEGDAWgBTXXUgpaSwO9HOrQBxGqOOS
FHsHEDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0B
AQsDggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJd
FI1UjL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHF
A145JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j
4WCv5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7c
WWOay6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvT
br6+bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs
369/Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2Ygh
PsypDo33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpw
EPVqTR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS
/mg1t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH
0thnUGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuT
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEkDCCA/ugAwIBAgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT
AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv
MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG
A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAw
MDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE
CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j
b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL
AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng
xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW
RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu
u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU
mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0
APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys
sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT
7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7
STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow
TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND
DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDAS
BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH
EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRj
bG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/
fWznVvOEFAAYZByPFx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9
fC7vf45B2zCX0OW51QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnch
DaMsXjQQTJu0iuG3qKEuCmUwOmc=
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEmzCCA4OgAwIBAgIMAMSvNBgypwaaSQ5iMA0GCSqGSIb3DQEBBQUAMIGMMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVT
VCBSb290IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTIx
MjEyMDIxMDMxWhcNMjIxMDIxMDIxMDMxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNV
BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoT
CkNGU1NMIFRFU1QxGzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqG
SIb3DQEJARYPdGVzdEB0ZXN0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAsRp1xSfIDoD/40Bo4Hls3sFn4dav5NgxbZGpVyGF7dJI9u0eEnL4
BUGssPaUFLWC83CZxujUEiEfE0oKX+uOhhGv3+j5xSTNM764m2eSiN53cdZtK05d
hwq9uS8LtjKOQeN1mQ5qmiqxBMdjkKgMsVw5lMCgoYKo57kaKFyXzdpNVDzqw+pt
HWmuNtDQjK3qT5Ma06mYPmIGYhIZYLY7oJGg9ZEaNR0GIw4zIT5JRsNiaSb5wTLw
aa0n/4vLJyVjLJcYmJBvZWj8g+taK+C4INu/jGux+bmsC9hq14tbOaTNAn/NE0qN
8oHwcRBEqfOdEYdZkxI5NWPiKNW/Q+AeXQIDAQABo4H6MIH3MB0GA1UdDgQWBBS3
0veEuqg51fusEM4p/YuWpBPsvTCBxAYDVR0jBIG8MIG5gBS30veEuqg51fusEM4p
/YuWpBPsvaGBkqSBjzCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
aWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkNGU1NMIFRFU1Qx
GzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqGSIb3DQEJARYPdGVz
dEB0ZXN0LmxvY2FsggwAxK80GDKnBppJDmIwDwYDVR0TBAgwBgEB/wIBADANBgkq
hkiG9w0BAQUFAAOCAQEAJ7r1EZYDwed6rS0+YKHdkRGRQ5Rz6A9DIVBPXrSMAGj3
F5EF2m/GJbhpVbnNJTVlgP9DDyabOZNxzdrCr4cHMkYYnocDdgAodnkw6GZ/GJTc
depbVTR4TpihFNzeDEGJePrEwM1DouGswpu97jyuCYZ3z1a60+a+3C1GwWaJ7Aet
Uqm+yLTUrMISsfnDPqJdM1NeqW3jiZ4IgcqJkieCCSpag9Xuzrp9q6rjmePvlQkv
qz020JGg6VijJ+c6Tf5y0XqbAhkBTqYtVamu9gEth9utn12EhdNjTZMPKMjjgFUd
H0N6yOEuQMl4ky7RxZBM0iPyeob6i4z2LEQilgv9MQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGnXFJ8gOgP/j
QGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLzcJnG6NQSIR8T
Sgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B43WZDmqaKrEE
x2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepPkxrTqZg+YgZi
EhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMslxiYkG9laPyD
61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850Rh1mTEjk1Y+Io
1b9D4B5dAgMBAAECggEAKHhjcSomDSptTwDo9mLI/h40HudwSlsc8GzYxZBjinUD
N2n39T9QbeMUE1xFenX/9qFEgq+xxnLLJx1EQacSapCgIAqdCO/f9HMgvGJumdg8
c0cMq1i9Bp7tu+OESZ5D48qWlOM2eQRIb08g8W11eRIaFmPuUPoKnuktkQuXpPJc
YbS/+JuA8SDwe6sV0cMCQuS+iHFfeGwWCKrDUkhLwcL3waW3od2XFyOeFFWFhl0h
HmM/mWKRuRdqR7hrmArTwFZVkB+o/1ywVYXIv+JQm0eNZ5PKLNJGL2f5oxbMR/JI
AoK0bAlJmYaFp96h1KpbPwLEL/0hHSWA7sAyJIgQAQKBgQDaEAZor/w4ZUTekT1+
cbId0yA+ikDXQOfXaNCSh9Pex+Psjd5zVVOqyVFJ29daRju3d7rmpN4Cm5V4h0l1
/2ad207rjCAnpCHtaddJWNyJzF2IL2IaoCZQRp0k7zOjBGQpoWDTwBaEin5CCv3P
kkdQkKz6FDP1xskHSLZr21/QCQKBgQDP6jXutEgGjf3yKpMFk/69EamJdon8clbt
hl7cOyWtobnZhdOWVZPe00Oo3Jag2aWgFFsm3EtwnUCnR4d4+fXRKS2LkhfIUZcz
cKy17Ileggdd8UGhL4RDrF/En9tJL86WcVkcoOrqLcGB2FLWrVhVpHFK74eLMCH/
uc/+ioPItQKBgHYoDsD08s7AGMQcoNx90MyWVLduhFnegoFW+wUa8jOZzieka6/E
wVQeR5yksZjpy3vLNYu6M83n7eLkM2rrm/fXGHlLcTTpm7SgEBZfPwivotKjEh5p
PrlqucWEk082lutz1RqHz+u7e1Rfzk2F7nx6GDBdeBYpw03eGXJx6QW5AoGBAIJq
4puyAEAET1fZNtHX7IGCk7sDXTi6LCbgE57HhzHr8V0t4fQ6CABMuvMwM1gATjEk
s6yjoLqqGUUUzDipanViBAy5fiuManC868lN7zkWDTLzQ3ytBqVAee4na/DziP27
ae9YTSLJwskE/alloLRP6zTbHUXE0n7LelmrX1DFAoGBAMFLl+Lu+WFgCHxBjn43
rHpJbQZQmsFhAMhkN4hsj6dJfAGn2gRLRiVRAika+8QF65xMZiVQWUVSUZADWERi
0SXGjzN1wYxO3Qzy3LYwws6fxFAq5lo79eb38yFT2lHdqK3x/QgiDSRVl+R6cExV
xQB518/lp2eIeMpglWByDwJX
-----END PRIVATE KEY-----

Binary file not shown.

View File

@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB7DCCAZKgAwIBAgIIE/Qz49ebG7kwCgYIKoZIzj0EAwIwTDELMAkGA1UEBhMC
VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
EDAOBgNVBAoTB2FjbWUuY28wHhcNMTcwNTIzMTk1MTQ0WhcNMTcwODIzMDE1NjQ0
WjBMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN
U2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHYWNtZS5jbzBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABEW8F+k/avvdBm/KRsuDnTZ3p+VuVdsqDF+aD9nIYeOhx5sj574y
hEIZOpgbEsi3BvqY63y2jYyPFodf25+CA9GjXjBcMA4GA1UdDwEB/wQEAwIFoDAd
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNV
HQ4EFgQUzDpu+HN89EC1M8aNl7f0Ln5JnnIwCgYIKoZIzj0EAwIDSAAwRQIgC4/r
urbw/pzE3LDA6GpIts6TVyzgftLLEfU2BzQsjp0CIQDo+sn8t7XC6JN4KKRr2ABl
ZI+JifgG+2KCy9ln2LxGJQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,14 @@
-----BEGIN PKCS7-----
MIICHQYJKoZIhvcNAQcCoIICDjCCAgoCAQExADALBgkqhkiG9w0BBwGgggHwMIIB
7DCCAZKgAwIBAgIIE/Qz49ebG7kwCgYIKoZIzj0EAwIwTDELMAkGA1UEBhMCVVMx
EzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEDAO
BgNVBAoTB2FjbWUuY28wHhcNMTcwNTIzMTk1MTQ0WhcNMTcwODIzMDE1NjQ0WjBM
MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2Fu
IEZyYW5jaXNjbzEQMA4GA1UEChMHYWNtZS5jbzBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABEW8F+k/avvdBm/KRsuDnTZ3p+VuVdsqDF+aD9nIYeOhx5sj574yhEIZ
OpgbEsi3BvqY63y2jYyPFodf25+CA9GjXjBcMA4GA1UdDwEB/wQEAwIFoDAdBgNV
HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4E
FgQUzDpu+HN89EC1M8aNl7f0Ln5JnnIwCgYIKoZIzj0EAwIDSAAwRQIgC4/rurbw
/pzE3LDA6GpIts6TVyzgftLLEfU2BzQsjp0CIQDo+sn8t7XC6JN4KKRr2ABlZI+J
ifgG+2KCy9ln2LxGJaEAMQA=
-----END PKCS7-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIIB7DCCAZKgAwIBAgIIE/Qz49ebG7kwCgYIKoZIzj0EAwIwTDELMAkGA1UEBhMC
VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
EDAOBgNVBAoTB2FjbWUuY28wHhcNMTcwNTIzMTk1MTQ0WhcNMTcwODIzMDE1NjQ0
WjBMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN
U2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHYWNtZS5jbzBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABEW8F+k/avvdBm/KRsuDnTZ3p+VuVdsqDF+aD9nIYeOhx5sj574y
hEIZOpgbEsi3BvqY63y2jYyPFodf25+CA9GjXjBcMA4GA1UdDwEB/wQEAwIFoDAd
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNV
HQ4EFgQUzDpu+HN89EC1M8aNl7f0Ln5JnnIwCgYIKoZIzj0EAwIDSAAwRQIgC4/r
urbw/pzE3LDA6GpIts6TVyzgftLLEfU2BzQsjp0CIQDo+sn8t7XC6JN4KKRr2ABl
ZI+JifgG+2KCy9ln2LxGJQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBgTCCASgCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBn9Ldie6BOcMHezn2dPuYqW
z/NoLYMLGNBqhOxUyEidYClI0JW2pWyUgT3A2UazFp1WgE94y7Z+2YlfRz+vcrKg
PzA9BgkqhkiG9w0BCQ4xMDAuMCwGA1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3
d3djbG91ZGZsYXJlLmNvbTAKBggqhkjOPQQDAgNHADBEAiBM+QRxe8u6rkdr10Jy
cxbR6NxrGrNeg5QqiOqF96JEmgIgDbtjd5e3y3I8W/+ih2us3WtMxgnTXfqPd48i
VLcv28Q=
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1 @@

Binary file not shown.

View File

@ -0,0 +1,3 @@
-----BEGIN PKCS7-----
MCcGCSqGSIb3DQEHAqAaMBgCAQExADALBgkqhkiG9w0BBwGgAKEAMQA=
-----END PKCS7-----

View File

@ -0,0 +1,2 @@
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----LSKFSKLF

Binary file not shown.

View File

@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,90B8A5792FA2FE75B2053582F3DF394F
yVY2xuth5fdJBg9gg+6eP3qTsr0CJ2mGEDW6rvYmYuATSRF1hVERrsznxJYjYLaw
JHec8FVr78y4aXxI/aFzlxLkS8f12WjTtIhzHwhzgSJDwVOXSRphnLAeHWnhEKLe
7kO+vzoTPIc3ECwdvtr6//z2tP1/sac+yIhL6C+x2rS5hFHhmDUXtILPxxfHJCiM
qtKiiOZz3W6008CeJMC9ZPlKHDvpq7aIL4rfVP/GkZ+/teQkgWNpMxac7+gWLKuK
109v6pu+8KT49D6SMsaZPvAb5PXcIB79ZCPI1JX0V26CKcswba4RHG/h1xifwyAF
OIvmK29mmFqbx5GPlUefRUuPwRJKCXFiK6LTdhCwLYodtXde4ibvOFYy4onGoVax
I5WVaOhQMqp+mxA6z7odrIvuFcQGixIA+peaaSbpNZSZGuxRvVefcdxPbJ+26Ijs
wq8uyalbwhKtjPTPNkMaaYzJdWS7wd2DS4RM9JT8Y1h6NTftCY3c+/txOlt5pQzW
T8n+NTd4o+PFOHzMnmEnrtf9Y/SSzXDB2OPCD95YdIXItQDdKcjK0NmnY8GNfkWL
G30NJNy3/DR7Sa5u4xuqNgcgTFhgZaOQ1IVB3p5VjknqAX3gWFu2DrqzbH45071A
He7VbdbzBpMHI2EdiCVOuK9fD/5sv25u9vVC2NHtG/YcoEQv+RB52TNHn9kdiMj1
gLaywPqGjFmaPxI0xX07BrL+D9RruUT1GAEyw4JAHuJZIyq3+V98wmV/pEqwc7hp
8WuSi6YddetfF4NPA5cGWt8qZ1it+wD/1ydQEAQsxdANqi0XVudYpYox02EoRS02
up0sd9zqz83pN9RyOOKtGcHdt85gb9DYRVeff1UszMaoVULxqxYetwtzpiHn6grL
DmnSk+DYgvXKOVt8tmSJysDTumhK1VN3xb34TYYJxeBOQJLzWFjGSELEpphZAQSj
rS4OM1FwoP48wvASGiWD4VUJ6v+6F+NDvJr01S+zWGLg1EeUZJmXGHW5GrGd4Kgx
3rdeOsrED9oXKp2cpgx9avXJ9upixja9MbAPp7RkSyeHMPvsuaI44xvOP3f0crmG
d/5CdBKVT7nFaeTGSx/78kHb3VJyopAMm9k0V3CheKwBXXSbXmV1+0muBxMHsEI3
aEKaI0y5cDfTewzo/U0l0kGtxF6kUPN1pdjFpAvssRlkGttFOC2nWxHwaNHpn7Kq
gFAlN6P4cyB6kb+LvckIYTZ/tV39dx7PfL0KG5TWjJ4a9GSoL1IrAhQq+Qv6oUEt
1vlejZoKyZ/35fni0fmeYNho+pCPimm6l+sHTuXkrWgGLr0S9O00HFLz11D7R4o9
7mF4JkMNztT+ENOdT4xQBi3OGjRGMwtE6PsQPfDeu13Vq6eDtdEGUdhW1kAsGnBi
eJRuysnGpnoWofJ7yS0+DhnS4GAVi907TMrQWwmez9V4CXl4NBc8X9T69TFL2LsW
2KU9NUXdiCRZqZHD41gd3+RuRA/oXh50V9oaow+uepwYKTFyzde5IH1/DgBd7tOd
Fa2fM5/zSA0uFPRb3yCVhRg5d6J9t5yaPAz7Jp0D1mDDGsMBD1O/FYJvWoANEwUX
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,48 @@
-----BEGIN CERTIFICATE-----
MIIEczCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG
EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp
bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv
cm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAw
MDAwWhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs
b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT
FHsHEDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0B
AQsDggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJd
FI1UjL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHF
A145JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j
4WCv5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7c
WWOay6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvT
br6+bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs
369/Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2Ygh
PsypDo33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpw
EPVqTR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS
/mg1t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH
0thnUGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuT
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEkDCCA/ugAwIBAgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT
AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv
MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG
A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAw
MDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE
CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j
b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL
AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng
xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW
RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu
u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU
mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0
APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys
sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT
7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7
STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow
TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND
DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDAS
BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH
EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRj
bG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/
fWznVvOEFAAYZByPFx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9
fC7vf45B2zCX0OW51QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnch
DaMsXjQQTJu0iuG3qKEuCmUwOmc=
-----END CERTIFICATE-----
SDFSDKjkfdlsdfj

View File

@ -0,0 +1,20 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvGKyz9ZzIXI/BFrtqbVQMmKQkPZGndyfV3AzeSb2ulbS/s5k
yNJMH/jKZiSCvZiJNnW+JNlJrgLxORMmPStPz/N/0L0vCTotQKZUiaBttFgHgobQ
LFsbMnumt9It5W/uOwgWI9binuzvqyPXywLlYwOq3jkOmA22ymhflzRrl6a3jzcY
hT9evxHl0gV4bN7KZ5p4wK/UUuG1uMEQLw87lUwRRHeW3ZG52VL38+redka+f5pa
SGKyG5j0oe1NPLqAjckNgqvDdPMY2gicmCq0VSLzTNpHRsURTUSJvC/iv34vVfba
gIYgTvm8BvGbJSlZqP4kEVlOfd3vmB0ttUeoDwIDAQABAoIBAHZdpXCFlA1d1U6N
O2s4a01dNOyAcVpa9xtfelgTLU9jomtLj3PG/uHP1oxbQHKUVxKK5JAOnwbg/mQY
LhydDCbjHlovpFAt56UJXXCkBoocDYvr3P0huXL80oIJY6EXtR4ONKsMJ5Qn12c2
vC3ogey2rzO1sf/EDigbcIR3AWtk1Tx8ZDUooktOFypIsDQgjjxXiURGssAlMPSh
6GVgO4JRRG6oRxEna7yDe7izmh/hC5sxSYLsEikCgYEAsBHhb/Qef5obRCSrfFuQ
41P7MCtGrXVxKD3iCDGQCzVbEbYGpmZnGsXSaHljp2FtnamaGGEudYziozGKPHjs
pbTbsLIDbmNwxz1WcaZ1iyIjtOxcAEqDod8hY4hL6SaxypwTHn4Ydbw2NGzp11Eg
Di4SVL82utjycATdKFvBzdsCgYB/3M+GMrt0Sh87rKcQLdL709Kzjcfhvm4HjIbJ
GSXGPCZaYMKaXRTdNAjtRKxMawc9qcf0xSBEHL0GkB158TzusDQtjP1anTcYOnl6
GsO4bRivp314iNlP4r3S3bIXqBxCGH3HbrvpdPFAN//qjYmAki2lFQZywfvbQOE8
oFQHwQKBgHqJkTck2DGlXQIwA7jirLggISXjSPlsG4w4LuhY9ivyNKLUi4x5k1cE
bX7SrRtJErQ1WaDN4TFG25xnysi5h+aPinuySatd0XmA5+dE1YjTqqShMO+lUpzi
PrOQl6Eva/uw5BDAcUH4AaXTNRvvtXQptUil9qXyOh6fszikA9Mm
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIB7jCCAVmgAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTEyMDkwNzIyMDAwNFoXDTEzMDkwNzIy
MDUwNFowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGd
MAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1C
cqhEvLFbu3MCAwEAAaMyMDAwDgYDVR0PAQH/BAQDAgCgMA0GA1UdDgQGBAQBAgME
MA8GA1UdIwQIMAaABAECAwQwCwYJKoZIhvcNAQEFA4GBABndWRIcfi+QB9Sakr+m
dYnXTgYCnFio53L2Z+6EHTGG+rEhWtUEGhL4p4pzXX4siAnjWvwcgXTo92cafcfi
uB7wRfK+NL9CTJdpN6cdL+fiNHzH8hsl3bj1nL0CSmdn2hkUWVLbLhSgWlib/I8O
aq+K7aVrgHkPnWeRiG6tl+ZA
-----END CERTIFICATE-----

Binary file not shown.

View File

@ -0,0 +1,9 @@
MIIB7jCCAVmgAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTEyMDkwNzIyMDAwNFoXDTEzMDkwNzIy
MDUwNFowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGd
MAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1C
cqhEvLFbu3MCAwEAAaMyMDAwDgYDVR0PAQH/BAQDAgCgMA0GA1UdDgQGBAQBAgME
MA8GA1UdIwQIMAaABAECAwQwCwYJKoZIhvcNAQEFA4GBABndWRIcfi+QB9Sakr+m
dYnXTgYCnFio53L2Z+6EHTGG+rEhWtUEGhL4p4pzXX4siAnjWvwcgXTo92cafcfi
uB7wRfK+NL9CTJdpN6cdL+fiNHzH8hsl3bj1nL0CSmdn2hkUWVLbLhSgWlib/I8O
aq+K7aVrgHkPnWeRiG6tl+ZA

Binary file not shown.

View File

@ -0,0 +1,28 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvGKyz9ZzIXI/BFrtqbVQMmKQkPZGndyfV3AzeSb2ulbS/s5k
yNJMH/jKZiSCvZiJNnW+JNlJrgLxORMmPStPz/N/0L0vCTotQKZUiaBttFgHgobQ
LFsbMnumt9It5W/uOwgWI9binuzvqyPXywLlYwOq3jkOmA22ymhflzRrl6a3jzcY
hT9evxHl0gV4bN7KZ5p4wK/UUuG1uMEQLw87lUwRRHeW3ZG52VL38+redka+f5pa
SGKyG5j0oe1NPLqAjckNgqvDdPMY2gicmCq0VSLzTNpHRsURTUSJvC/iv34vVfba
gIYgTvm8BvGbJSlZqP4kEVlOfd3vmB0ttUeoDwIDAQABAoIBAHZdpXCFlA1d1U6N
O2s4a01dNOyAcVpa9xtfelgTLU9jomtLj3PG/uHP1oxbQHKUVxKK5JAOnwbg/mQY
LhydDCbjHlovpFAt56UJXXCkBoocDYvr3P0huXL80oIJY6EXtR4ONKsMJ5Qn12c2
vC3ogey2rzO1sf/EDigbcIR3AWtk1Tx8ZDUooktOFypIsDQgjjxXiURGssAlMPSh
1BFz4StRUK4bESaja0GiHwbuxHa+XYEBlK5OqMo/fpWqpgHhV/42+7wdcBMJsMr8
rFBe6m+r6TTbLSGJNowyd05XrjoAI35qduckpJ3Voun90i4ynTudjdJ/vHpIqB74
qQLFW2ECgYEA+GSRVqobaKKakNUFGmK0I5T5Tikz5f137YXXER6aLtDQNiSrlXNi
0aphkC/EfRO3oNvamq5+55bmmgDVoNNPDfpajKz+LZyG8GC2EXlTKO0hZS64KRRl
C+bd+ZsYiUDImNVRbIHN82f+BQgsgXlTaWpBOrEqmoePO/J44O4eX3cCgYEAwieq
amY4UaY+MhWPJFRK1y9M3hM8+N9N/35CFewQUdFJosC6vVQ4t8jNkSOxVQdgbNwE
i/bTBgIwg82JJYbBUPuCVeTT3i6zxymf/FLumrI73URD81IN6FiH1skg0hSFrvs0
6GVgO4JRRG6oRxEna7yDe7izmh/hC5sxSYLsEikCgYEAsBHhb/Qef5obRCSrfFuQ
41P7MCtGrXVxKD3iCDGQCzVbEbYGpmZnGsXSaHljp2FtnamaGGEudYziozGKPHjs
pbTbsLIDbmNwxz1WcaZ1iyIjtOxcAEqDod8hY4hL6SaxypwTHn4Ydbw2NGzp11Eg
Di4SVL82utjycATdKFvBzdsCgYB/3M+GMrt0Sh87rKcQLdL709Kzjcfhvm4HjIbJ
GSXGPCZaYMKaXRTdNAjtRKxMawc9qcf0xSBEHL0GkB158TzusDQtjP1anTcYOnl6
GsO4bRivp314iNlP4r3S3bIXqBxCGH3HbrvpdPFAN//qjYmAki2lFQZywfvbQOE8
oFQHwQKBgHqJkTck2DGlXQIwA7jirLggISXjSPlsG4w4LuhY9ivyNKLUi4x5k1cE
bX7SrRtJErQ1WaDN4TFG25xnysi5h+aPinuySatd0XmA5+dE1YjTqqShMO+lUpzi
PrOQl6Eva/uw5BDAcUH4AaXTNRvvtXQptUil9qXyOh6fszikA9Mm
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MGgCAQEEHCGXsrNo2xfy8+zd4Pzj8rcQ5KqQO43au1t/7nugBwYFK4EEACGhPAM6
AASJodCTtj5aYXnWxMiYhwjEgNQJJbNzJFEbsGJX9pCWZC673ammTWFHMjnMPkS/
9eU5YeW40BHqfw==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,19 @@
-----BEGIN NEW CERTIFICATE REQUEST-----
MIIDCTCCAfMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTWdoYxX4KN51fP
WxQAyGH++VsPbfpAoXIbCPXSmU04BvIxyjzpHQ0ChMKkT/2VNcUeFJwk2fCf+ZwU
f0raTQTplofwkckE0gEYA3WcEfJp+hbvbTb/2recsf+JE6JACYJe2Uu5wsjtrE5j
A+7aT2BEU9RWzBdSy/5281ZfW3PArqcWaf8+RUyA3WRxVWmjmhFsVB+mdNLhCpW0
C0QNMYR1ppEZiKVnEdao8gcI5sOvSd+35t8g82aPXcNSPU6jKcx1YNUPX5wgPEmu
+anfc9RliQbYqqJYVODgBmV8IR5grw93yTsODoWKtFQ4PKVlnt9CD8AS/iSMQYm3
OUogqgMCAwEAAaA/MD0GCSqGSIb3DQEJDjEwMC4wLAYDVR0RBCUwI4IOY2xvdWRm
bGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAsGCSqGSIb3DQEBCwOCAQEAl809
gk9uZkRK+MJVYDSLjgGR2xqk5qOwnhovnispA7N3Z1GshodJRQa6ngNCKuXIm2/6
AxB9kDGK14n186Qq4odXqHSHs8FG9i0zUcBXeLv1rPAKtwKTas/SLmsOpPgWPZFa
iYiHHeu4HjOQoF987d7uGRYwc3xfstKwJsEXc12eCw2NH8TM1tJgSc/o6CzIpA91
QnZKhx6uGM4xI2gnOaJA1YikNhyFGBuOGMZgd0k2+/IcR2pg0z4pc5oQw1bXLANx
anqlA/MDrCM9v9019bRJ73zK8LQ3k/FW61PA9nL7RZ8ku65R+uYcVEdLa8pUeqnH
cJZNboDRsItpccZuRQ==
-----END NEW CERTIFICATE REQUEST-----

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIJLKycmoCAk4HqlJGdsuFyHsxfIheKsLH91tS/TNP5OOoAcGBSuBBAAK
oUQDQgAEBkmL7cvC2cgchzfSuUZPGnzH0FqBtf3kGhSllQiIzGDn4envPXNqp+93
V2NZ8VT+Aba4ln2Vbp9gYrKquut5Zg==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICzDCCAbQCAQAwgYYxCzAJBgNVBAYTAkVOMQ0wCwYDVQQIDARub25lMQ0wCwYD
VQQHDARub25lMRIwEAYDVQQKDAlXaWtpcGVkaWExDTALBgNVBAsMBG5vbmUxGDAW
BgNVBAMMDyoud2lraXBlZGlhLm9yZzEcMBoGCSqGSIb3DQEJARYNbm9uZUBub25l
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMP/U8RlcCD6E8AL
PT8LLUR9ygyygPCaSmIEC8zXGJung3ykElXFRz/Jc/bu0hxCxi2YDz5IjxBBOpB/
kieG83HsSmZZtR+drZIQ6vOsr/ucvpnB9z4XzKuabNGZ5ZiTSQ9L7Mx8FzvUTq5y
57HhA7ECAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4IBAQBn8OCVOIx+n0AS6WbEmYDR
SspR9xOCoOwYfamB+2Bpmt82R01zJ/kaqzUtZUjaGvQvAaz5lUwoMdaO0X7I5Xfl
sllMFDaYoGD4Rru4s8gz2qG/QHWA8uPXzJVAj6X0olbIdLTEqTKsnBj4Zr1AJCNy
/YcG4ouLJr140o26MhwBpoCRpPjAgdYMH60BYfnc4/DILxMVqR9xqK1s98d6Ob/+
3wHFK+S7BRWrJQXcM8veAexXuk9lHQ+FgGfD0eSYGz0kyP26Qa2pLTwumjt+nBPl
rfJxaLHwTQ/1988G0H35ED0f9Md5fzoKi5evU1wG5WRxdEUPyt3QUXxdQ69i0C+7
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICzDCCAbQCAQAwgYYxCzAJBgNVBAYTAkVOMQ0wCwYDVQQIDARub25lMQ0wCwYD
VQQHDARub25lMRIwEAYDVQQKDAlXaWtpcGVkaWExDTALBgNVBAsMBG5vbmUxGDAW
BgNVBAMMDyoud2lraXBlZGlhLm9yZzEcMBoGCSqGSIb3DQEJARYNbm9uZUBub25l
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMP/U8RlcCD6E8AL
PT8LLUR9ygyygPCaSmIEC8zXGJung3ykElXFRz/Jc/bu0hxCxi2YDz5IjxBBOpB/
kieG83HsSmZZtR+drZIQ6vOsr/ucvpnB9z4XzKuabNGZ5ZiTSQ9L7Mx8FzvUTq5y
/ArIuM+FBeuno/IV8zvwAe/VRa8i0QjFXT9vBBp35aeatdnJ2ds50yKCsHHcjvtr
9/8zPVqqmhl2XFS3Qdqlsprzbgksom67OobJGjaV+fNHNQ0o/rzP//Pl3i7vvaEG
7Ff8tQhEwR9nJUR1T6Z7ln7S6cOr23YozgWVkEJ/dSr6LAopb+cZ88FzW5NszU6i
57HhA7ECAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4IBAQBn8OCVOIx+n0AS6WbEmYDR
SspR9xOCoOwYfamB+2Bpmt82R01zJ/kaqzUtZUjaGvQvAaz5lUwoMdaO0X7I5Xfl
sllMFDaYoGD4Rru4s8gz2qG/QHWA8uPXzJVAj6X0olbIdLTEqTKsnBj4Zr1AJCNy
/YcG4ouLJr140o26MhwBpoCRpPjAgdYMH60BYfnc4/DILxMVqR9xqK1s98d6Ob/+
3wHFK+S7BRWrJQXcM8veAexXuk9lHQ+FgGfD0eSYGz0kyP26Qa2pLTwumjt+nBPl
rfJxaLHwTQ/1988G0H35ED0f9Md5fzoKi5evU1wG5WRxdEUPyt3QUXxdQ69i0C+7
-----END CERTIFICATE REQUEST-----

15
vendor/github.com/cloudflare/cfssl/info/info.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// Package info contains the definitions for the info endpoint
package info
// Req is the request struct for an info API request.
type Req struct {
Label string `json:"label"`
Profile string `json:"profile"`
}
// Resp is the response for an Info API request.
type Resp struct {
Certificate string `json:"certificate"`
Usage []string `json:"usages"`
ExpiryString string `json:"expiry"`
}

249
vendor/github.com/cloudflare/cfssl/initca/initca.go generated vendored Normal file
View File

@ -0,0 +1,249 @@
// Package initca contains code to initialise a certificate authority,
// generating a new root key and certificate.
package initca
import (
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"time"
"github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/csr"
cferr "github.com/cloudflare/cfssl/errors"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/log"
"github.com/cloudflare/cfssl/signer"
"github.com/cloudflare/cfssl/signer/local"
)
// validator contains the default validation logic for certificate
// authority certificates. The only requirement here is that the
// certificate have a non-empty subject field.
func validator(req *csr.CertificateRequest) error {
if req.CN != "" {
return nil
}
if len(req.Names) == 0 {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
}
for i := range req.Names {
if csr.IsNameEmpty(req.Names[i]) {
return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
}
}
return nil
}
// New creates a new root certificate from the certificate request.
func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
policy := CAPolicy()
if req.CA != nil {
if req.CA.Expiry != "" {
policy.Default.ExpiryString = req.CA.Expiry
policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
if err != nil {
return
}
}
if req.CA.Backdate != "" {
policy.Default.Backdate, err = time.ParseDuration(req.CA.Backdate)
if err != nil {
return
}
}
policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
if req.CA.PathLength != 0 && req.CA.PathLenZero {
log.Infof("ignore invalid 'pathlenzero' value")
} else {
policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
}
}
g := &csr.Generator{Validator: validator}
csrPEM, key, err = g.ProcessRequest(req)
if err != nil {
log.Errorf("failed to process request: %v", err)
key = nil
return
}
priv, err := helpers.ParsePrivateKeyPEM(key)
if err != nil {
log.Errorf("failed to parse private key: %v", err)
return
}
s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
if err != nil {
log.Errorf("failed to create signer: %v", err)
return
}
signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
cert, err = s.Sign(signReq)
return
}
// NewFromPEM creates a new root certificate from the key file passed in.
func NewFromPEM(req *csr.CertificateRequest, keyFile string) (cert, csrPEM []byte, err error) {
privData, err := helpers.ReadBytes(keyFile)
if err != nil {
return nil, nil, err
}
priv, err := helpers.ParsePrivateKeyPEM(privData)
if err != nil {
return nil, nil, err
}
return NewFromSigner(req, priv)
}
// RenewFromPEM re-creates a root certificate from the CA cert and key
// files. The resulting root certificate will have the input CA certificate
// as the template and have the same expiry length. E.g. the existing CA
// is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
// will be valid from now and expire in one year as well.
func RenewFromPEM(caFile, keyFile string) ([]byte, error) {
caBytes, err := helpers.ReadBytes(caFile)
if err != nil {
return nil, err
}
ca, err := helpers.ParseCertificatePEM(caBytes)
if err != nil {
return nil, err
}
keyBytes, err := helpers.ReadBytes(keyFile)
if err != nil {
return nil, err
}
key, err := helpers.ParsePrivateKeyPEM(keyBytes)
if err != nil {
return nil, err
}
return RenewFromSigner(ca, key)
}
// NewFromSigner creates a new root certificate from a crypto.Signer.
func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
policy := CAPolicy()
if req.CA != nil {
if req.CA.Expiry != "" {
policy.Default.ExpiryString = req.CA.Expiry
policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
if err != nil {
return nil, nil, err
}
}
policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
log.Infof("ignore invalid 'pathlenzero' value")
} else {
policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
}
}
csrPEM, err = csr.Generate(priv, req)
if err != nil {
return nil, nil, err
}
s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
if err != nil {
log.Errorf("failed to create signer: %v", err)
return
}
signReq := signer.SignRequest{Request: string(csrPEM)}
cert, err = s.Sign(signReq)
return
}
// RenewFromSigner re-creates a root certificate from the CA cert and crypto.Signer.
// The resulting root certificate will have ca certificate
// as the template and have the same expiry length. E.g. the existing CA
// is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
// will be valid from now and expire in one year as well.
func RenewFromSigner(ca *x509.Certificate, priv crypto.Signer) ([]byte, error) {
if !ca.IsCA {
return nil, errors.New("input certificate is not a CA cert")
}
// matching certificate public key vs private key
switch {
case ca.PublicKeyAlgorithm == x509.RSA:
var rsaPublicKey *rsa.PublicKey
var ok bool
if rsaPublicKey, ok = priv.Public().(*rsa.PublicKey); !ok {
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
}
if ca.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 {
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
}
case ca.PublicKeyAlgorithm == x509.ECDSA:
var ecdsaPublicKey *ecdsa.PublicKey
var ok bool
if ecdsaPublicKey, ok = priv.Public().(*ecdsa.PublicKey); !ok {
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
}
if ca.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 {
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
}
default:
return nil, cferr.New(cferr.PrivateKeyError, cferr.NotRSAOrECC)
}
req := csr.ExtractCertificateRequest(ca)
cert, _, err := NewFromSigner(req, priv)
return cert, err
}
// CAPolicy contains the CA issuing policy as default policy.
var CAPolicy = func() *config.Signing {
return &config.Signing{
Default: &config.SigningProfile{
Usage: []string{"cert sign", "crl sign"},
ExpiryString: "43800h",
Expiry: 5 * helpers.OneYear,
CAConstraint: config.CAConstraint{IsCA: true},
},
}
}
// Update copies the CA certificate, updates the NotBefore and
// NotAfter fields, and then re-signs the certificate.
func Update(ca *x509.Certificate, priv crypto.Signer) (cert []byte, err error) {
copy, err := x509.ParseCertificate(ca.Raw)
if err != nil {
return
}
validity := ca.NotAfter.Sub(ca.NotBefore)
copy.NotBefore = time.Now().Round(time.Minute).Add(-5 * time.Minute)
copy.NotAfter = copy.NotBefore.Add(validity)
cert, err = x509.CreateCertificate(rand.Reader, copy, copy, priv.Public(), priv)
if err != nil {
return
}
cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert})
return
}

View File

@ -0,0 +1,385 @@
package initca
import (
"bytes"
"crypto/ecdsa"
"crypto/rsa"
"io/ioutil"
"strings"
"testing"
"time"
"github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/csr"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/signer"
"github.com/cloudflare/cfssl/signer/local"
)
var validKeyParams = []csr.BasicKeyRequest{
{A: "rsa", S: 2048},
{A: "rsa", S: 3072},
{A: "rsa", S: 4096},
{A: "ecdsa", S: 256},
{A: "ecdsa", S: 384},
{A: "ecdsa", S: 521},
}
var validCAConfigs = []csr.CAConfig{
{PathLength: 0, PathLenZero: true},
{PathLength: 0, PathLenZero: false},
{PathLength: 2},
{PathLength: 2, Expiry: "1h"},
// invalid PathLenZero value will be ignored
{PathLength: 2, PathLenZero: true},
}
var invalidCAConfig = csr.CAConfig{
PathLength: 2,
// Expiry must be a duration string
Expiry: "2116/12/31",
}
var csrFiles = []string{
"testdata/rsa2048.csr",
"testdata/rsa3072.csr",
"testdata/rsa4096.csr",
"testdata/ecdsa256.csr",
"testdata/ecdsa384.csr",
"testdata/ecdsa521.csr",
}
var testRSACAFile = "testdata/5min-rsa.pem"
var testRSACAKeyFile = "testdata/5min-rsa-key.pem"
var testECDSACAFile = "testdata/5min-ecdsa.pem"
var testECDSACAKeyFile = "testdata/5min-ecdsa-key.pem"
var invalidCryptoParams = []csr.BasicKeyRequest{
// Weak Key
{A: "rsa", S: 1024},
// Bad param
{A: "rsaCrypto", S: 2048},
{A: "ecdsa", S: 2000},
}
func TestInitCA(t *testing.T) {
var req *csr.CertificateRequest
hostname := "cloudflare.com"
for _, param := range validKeyParams {
for _, caconfig := range validCAConfigs {
req = &csr.CertificateRequest{
Names: []csr.Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: hostname,
Hosts: []string{hostname, "www." + hostname},
KeyRequest: &param,
CA: &caconfig,
}
certBytes, _, keyBytes, err := New(req)
if err != nil {
t.Fatal("InitCA failed:", err)
}
key, err := helpers.ParsePrivateKeyPEM(keyBytes)
if err != nil {
t.Fatal("InitCA private key parsing failed:", err)
}
cert, err := helpers.ParseCertificatePEM(certBytes)
if err != nil {
t.Fatal("InitCA cert parsing failed:", err)
}
// Verify key parameters.
switch req.KeyRequest.Algo() {
case "rsa":
if cert.PublicKey.(*rsa.PublicKey).N.BitLen() != param.Size() {
t.Fatal("Cert key length mismatch.")
}
if key.(*rsa.PrivateKey).N.BitLen() != param.Size() {
t.Fatal("Private key length mismatch.")
}
case "ecdsa":
if cert.PublicKey.(*ecdsa.PublicKey).Curve.Params().BitSize != param.Size() {
t.Fatal("Cert key length mismatch.")
}
if key.(*ecdsa.PrivateKey).Curve.Params().BitSize != param.Size() {
t.Fatal("Private key length mismatch.")
}
}
// Verify CA MaxPathLen
if caconfig.PathLength == 0 && cert.MaxPathLenZero != caconfig.PathLenZero {
t.Fatalf("fail to init a CA cert with specified CA pathlen zero: expect %v, got %v", caconfig.PathLenZero, cert.MaxPathLenZero)
}
if caconfig.PathLength != 0 {
if cert.MaxPathLen != caconfig.PathLength {
t.Fatalf("fail to init a CA cert with specified CA pathlen: expect %d, got %d", caconfig.PathLength, cert.MaxPathLen)
}
if cert.MaxPathLenZero != false {
t.Fatalf("fail to init a CA cert with specified CA pathlen zero: expect false, got %t", cert.MaxPathLenZero)
}
}
// Replace the default CAPolicy with a test (short expiry) version.
CAPolicy = func() *config.Signing {
return &config.Signing{
Default: &config.SigningProfile{
Usage: []string{"cert sign", "crl sign"},
ExpiryString: "300s",
Expiry: 300 * time.Second,
CAConstraint: config.CAConstraint{IsCA: true},
},
}
}
// Start a signer
s, err := local.NewSigner(key, cert, signer.DefaultSigAlgo(key), nil)
if err != nil {
t.Fatal("Signer Creation error:", err)
}
s.SetPolicy(CAPolicy())
// Sign RSA and ECDSA customer CSRs.
for _, csrFile := range csrFiles {
csrBytes, err := ioutil.ReadFile(csrFile)
if err != nil {
t.Fatal("CSR loading error:", err)
}
req := signer.SignRequest{
Request: string(csrBytes),
Hosts: signer.SplitHosts(hostname),
Profile: "",
Label: "",
}
bytes, err := s.Sign(req)
if err != nil {
t.Fatal(err)
}
customerCert, _ := helpers.ParseCertificatePEM(bytes)
if customerCert.SignatureAlgorithm != s.SigAlgo() {
t.Fatal("Signature Algorithm mismatch")
}
err = customerCert.CheckSignatureFrom(cert)
if err != nil {
t.Fatal("Signing CSR failed.", err)
}
}
}
}
}
func TestInvalidCAConfig(t *testing.T) {
hostname := "example.com"
req := &csr.CertificateRequest{
Names: []csr.Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: hostname,
Hosts: []string{hostname, "www." + hostname},
KeyRequest: &validKeyParams[0],
CA: &invalidCAConfig,
}
_, _, _, err := New(req)
if err == nil {
t.Fatal("InitCA with bad CAConfig should fail:", err)
}
}
func TestInvalidCryptoParams(t *testing.T) {
var req *csr.CertificateRequest
hostname := "cloudflare.com"
for _, invalidParam := range invalidCryptoParams {
req = &csr.CertificateRequest{
Names: []csr.Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: hostname,
Hosts: []string{hostname, "www." + hostname},
KeyRequest: &invalidParam,
}
_, _, _, err := New(req)
if err == nil {
t.Fatal("InitCA with bad params should fail:", err)
}
if !strings.Contains(err.Error(), `"code":2400`) {
t.Fatal(err)
}
}
}
type validation struct {
r *csr.CertificateRequest
v bool
}
var testValidations = []validation{
{&csr.CertificateRequest{}, false},
{&csr.CertificateRequest{
CN: "test CA",
}, true},
{&csr.CertificateRequest{
Names: []csr.Name{{}},
}, false},
{&csr.CertificateRequest{
Names: []csr.Name{
{O: "Example CA"},
},
}, true},
}
func TestValidations(t *testing.T) {
for i, tv := range testValidations {
err := validator(tv.r)
if tv.v && err != nil {
t.Fatalf("%v", err)
}
if !tv.v && err == nil {
t.Fatalf("%d: expected error, but no error was reported", i)
}
}
}
func TestRenewRSA(t *testing.T) {
certPEM, err := RenewFromPEM(testRSACAFile, testRSACAKeyFile)
if err != nil {
t.Fatal(err)
}
// must parse ok
cert, err := helpers.ParseCertificatePEM(certPEM)
if err != nil {
t.Fatal(err)
}
if !cert.IsCA {
t.Fatal("renewed CA certificate is not CA")
}
// cert expiry must be 5 minutes
expiry := cert.NotAfter.Sub(cert.NotBefore).Seconds()
if expiry >= 301 || expiry <= 299 {
t.Fatal("expiry is not correct:", expiry)
}
// check subject
if cert.Subject.CommonName != "" {
t.Fatal("Bad CommonName")
}
if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "US" {
t.Fatal("Bad Subject")
}
if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "CloudFlare, Inc." {
t.Fatal("Bad Subject")
}
}
func TestRenewECDSA(t *testing.T) {
certPEM, err := RenewFromPEM(testECDSACAFile, testECDSACAKeyFile)
if err != nil {
t.Fatal(err)
}
// must parse ok
cert, err := helpers.ParseCertificatePEM(certPEM)
if err != nil {
t.Fatal(err)
}
if !cert.IsCA {
t.Fatal("renewed CA certificate is not CA")
}
// cert expiry must be 5 minutes
expiry := cert.NotAfter.Sub(cert.NotBefore).Seconds()
if expiry >= 301 || expiry <= 299 {
t.Fatal("expiry is not correct:", expiry)
}
// check subject
if cert.Subject.CommonName != "" {
t.Fatal("Bad CommonName")
}
if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "US" {
t.Fatal("Bad Subject")
}
if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "CloudFlare, Inc." {
t.Fatal("Bad Subject")
}
}
func TestRenewMismatch(t *testing.T) {
_, err := RenewFromPEM(testECDSACAFile, testRSACAKeyFile)
if err == nil {
t.Fatal("Fail to detect cert/key mismatch")
}
}
func TestRenew(t *testing.T) {
in, err := ioutil.ReadFile(testECDSACAFile)
if err != nil {
t.Fatal(err)
}
cert, err := helpers.ParseCertificatePEM(in)
if err != nil {
t.Fatal(err)
}
in, err = ioutil.ReadFile(testECDSACAKeyFile)
if err != nil {
t.Fatal(err)
}
priv, err := helpers.ParsePrivateKeyPEM(in)
if err != nil {
t.Fatal(err)
}
renewed, err := Update(cert, priv)
if err != nil {
t.Fatal(err)
}
newCert, err := helpers.ParseCertificatePEM(renewed)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(newCert.RawSubjectPublicKeyInfo, cert.RawSubjectPublicKeyInfo) {
t.Fatal("Update returned a certificate with different subject public key info")
}
if !bytes.Equal(newCert.RawSubject, cert.RawSubject) {
t.Fatal("Update returned a certificate with different subject info")
}
if !bytes.Equal(newCert.RawIssuer, cert.RawIssuer) {
t.Fatal("Update returned a certificate with different issuer info")
}
}

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIA8OzPeVZT0cXTAPdcXYefLRIqyUXa0f0SgYMJ2J1AVcoAoGCCqGSM49
AwEHoUQDQgAEoCV+bVOLTJMy38j50sc3vE5k41GMRgriFJt0g0OVX8yaOZ93CZTI
7LzfGbMU+KqWTgOwGhrPvpusep3fjw+dAQ==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICUDCCAfagAwIBAgIIec5PjdpJcNYwCgYIKoZIzj0EAwIwejELMAkGA1UEBhMC
VVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNVBAsTGlRlc3QgQ2Vy
dGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYD
VQQIEwpDYWxpZm9ybmlhMB4XDTE1MTAwODIzMDEwMFoXDTE1MTAwODIzMDYwMFow
ejELMAkGA1UEBhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNV
BAsTGlRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEoCV+bVOLTJMy38j50sc3vE5k41GMRgriFJt0g0OVX8yaOZ93CZTI7Lzf
GbMU+KqWTgOwGhrPvpusep3fjw+dAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud
EwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFDpLhSKBN3njfb6cXQCdRLzCZt0ZMB8G
A1UdIwQYMBaAFDpLhSKBN3njfb6cXQCdRLzCZt0ZMAoGCCqGSM49BAMCA0gAMEUC
IFU3BmzntGGeXZu2qWZx249nYn37S0AkCnQ3rUtI31bdAiEAsPICnZ+GB8yCN26N
OL+N8dHvXiOvZ9/Vl488pyWOccY=
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAtrYWs9ao2CpLWWLMyJJr3Bw7eJu3vSImzoqsBuhAREMaeuHm
vAwqbByVpdxu1o+t0u6cMp/1M4YwDSxD4Ny3zEUUGse6yZpyph0+whdHSn1LOCxY
KVwMtcYaEswenm0a+s/b9BYpbLv6lPoJ8+6bQNDuyyracDzlvGgk/HabemqDly4+
W64tlrMUDHBuHHIm5EMF1sqVcinLCS8KsVDVfg4qKfzsZbTw0dDo5GZh1lPslkk9
y8NzRltZjfJ3y5acv7SvIlETpy41VxScplR+Ot/6sXNJY3aEBT10smPXPABDeWjx
FbnU5xacL/pC7pnKy734sL4lkvzKPDWZPsNMEwIDAQABAoIBAHIFHBHKib+sVS1I
7MbWKR1JOQvBEV6kK1eFTmlZEpIG1kWNJ/J+HRMum2zQLRMUwsL5SNyG2fv3Z5Ew
6IMw+joteahkr/oTuixT39A7uq+PlRtPAQ1+digRoj/MxebT65xNjtO56MwEWxIR
H5jsdFJ0kDCVY4/bUPrMexhZ5Bj1xM3j8wpCPlVv2b9Ic/FUD9p6tOZDFhfSluiE
87VsFHUImNvu4p/BAKUuKiz58cPNDHPAABsPrJR2SVU59roC4QtEmaxbmDkXUtB1
+o+ypJQ0saqoffzHq7URebrJU9u+AV51UWaqHjg5OAe8eElOou6MHYX8R9cWZmJX
UQKPyVECgYEAyLqstNHtA7R7+r4bW8Tr/kF7z+VvCfV9wB6TPT+ycuv3aU5+HYgR
YRs2RBRtwI625hPk7AXEdbMt3SKoKjcMNMSD3qUK+fJFEyvOqRXiMJ2pLg04GlYZ
cOInJd0T1q3O2cNLZwcWB1L0/KiV0dYHc4p+p5hisai3T9w7QthTUr8CgYEA6QVW
jcsSBRFCokf/GKpTCVXIeqDSwrcEwoZh/RN6PlvgDwjw08G2IxKdAFs3/wxbKWHT
xss+LQiMyBL8aRJvBUfotj5e5ZYESaSDqdeYv0Sydl1vfxcknHpTBRUdbyDtsOQn
4X1ZEmfa9vFWS5P9fTFBC0BU2zzrhSlfQb6g360CgYBmnT+zBGo07aw/p7XWuRmn
lhRUWEbmgXAyqa69rfVs2IJXfD/umuO/j6izLvpYaNzJS7xIiD5BqUK1/ISZaCC+
TQPY6uhslFSJk2iHed9y2PZmy2010XQaCBLZQWZl5d6L5lGCrtWtEtSY4RoN9mtC
vrc2uCkkB0sG8V/+MRaPgwKBgBiML2oQkn1mLBbcbssyZjz9hHkmqA1LKn0zmu8G
NkKLezcaQgSMy5s2QsPe2C9OJexeGek/T/V+iRYqqdyHzJpJ0QIh3+1fuGPpqNUj
mTvNCN/fR/ejgH/bgxNt/gPO/Ds+TdU7Vz7RIggRtH2RwYqGvctpo4bVDBqjGR3b
7yahAoGAAgH97uN2FU1ffK0OAfMA1N58ikq/bg07KnJxO2CP5hrgsWK2ZVfeHUmU
3k+xqQHCIuew55yO0tARTrFAh3Rj+zarA+PrtnzqW82wCIn8Fym3PFzbK2qrIMie
yp0p4nBXsRmzinrPWKUYlFyRNY3Tcbstm5gUw2S4czSwwQeM/No=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID3DCCAsSgAwIBAgIIfbm2I1hwBa8wDQYJKoZIhvcNAQELBQAwejELMAkGA1UE
BhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNVBAsTGlRlc3Qg
Q2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMw
EQYDVQQIEwpDYWxpZm9ybmlhMB4XDTE1MTAwODIwMjEwMFoXDTE1MTAwODIwMjYw
MFowejELMAkGA1UEBhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAh
BgNVBAsTGlRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4g
RnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAtrYWs9ao2CpLWWLMyJJr3Bw7eJu3vSImzoqsBuhAREMa
euHmvAwqbByVpdxu1o+t0u6cMp/1M4YwDSxD4Ny3zEUUGse6yZpyph0+whdHSn1L
OCxYKVwMtcYaEswenm0a+s/b9BYpbLv6lPoJ8+6bQNDuyyracDzlvGgk/HabemqD
ly4+W64tlrMUDHBuHHIm5EMF1sqVcinLCS8KsVDVfg4qKfzsZbTw0dDo5GZh1lPs
lkk9y8NzRltZjfJ3y5acv7SvIlETpy41VxScplR+Ot/6sXNJY3aEBT10smPXPABD
eWjxFbnU5xacL/pC7pnKy734sL4lkvzKPDWZPsNMEwIDAQABo2YwZDAOBgNVHQ8B
Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQUCHoGEI1RZ8JN
7UZ4zcTRll8nnnAwHwYDVR0jBBgwFoAUCHoGEI1RZ8JN7UZ4zcTRll8nnnAwDQYJ
KoZIhvcNAQELBQADggEBAHRcbd6cSXV6IuT4jLV8k6OUUlxzobbiRnXJrLjy9Anx
tyIUWv2XSh/4IEJa+/MLNIb28gU9Sa2y4GV1qAgOM5qUM2iQJyLem0pTg0WTVKlj
ytEK1kUwQCNkc/xpDrPo5CbN3aDuW/VPntOJL1GSQzS7jzK3NeQ9sah9YYhk4Wsk
jzHVI1sX+qzcuUqCIPhqmGR0JE8ZI5YzbMTZ4/B+oWxZ7EyzB8O+v6HVD4eQFBSq
tyGhGbh7mUvuMpVJ8FIX4BA7QL+RwqNNtAMZKcxPjhy5I23nVclbTCz/NC2Dgp8H
13uQsEpUZ65clgiTo4LuPzPiIouZh5cBWP4gGqbyyS4=
-----END CERTIFICATE-----

View File

@ -0,0 +1,11 @@
1. To generate 5min-rsa.pem and 5min-rsa-key.pem
```
$ GOPATH/bin/cfssl gencert -initca ca_csr_rsa.json | GOPATH/bin/cfssljson -bare 5min-rsa
```
2. To generate 5min-ecdsa.pem and 5min-ecdsa-key.pem
```
$ GOPATH/bin/cfssl gencert -initca ca_csr_ecdsa.json | GOPATH/bin/cfssljson -bare 5min-ecdsa
```
The above commands will generate 5min-rsa.csr and 5min-ecdsa.csr as well, but those
files can be ignored.

View File

@ -0,0 +1,18 @@
{
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "US",
"L": "San Francisco",
"ST": "California",
"O": "CloudFlare, Inc.",
"OU": "Test Certificate Authority"
}
],
"ca": {
"expiry": "5m"
}
}

View File

@ -0,0 +1,18 @@
{
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "San Francisco",
"ST": "California",
"O": "CloudFlare, Inc.",
"OU": "Test Certificate Authority"
}
],
"ca": {
"expiry": "5m"
}
}

View File

@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBgTCCASgCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBn9Ldie6BOcMHezn2dPuYqW
z/NoLYMLGNBqhOxUyEidYClI0JW2pWyUgT3A2UazFp1WgE94y7Z+2YlfRz+vcrKg
PzA9BgkqhkiG9w0BCQ4xMDAuMCwGA1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3
d3djbG91ZGZsYXJlLmNvbTAKBggqhkjOPQQDAgNHADBEAiBM+QRxe8u6rkdr10Jy
cxbR6NxrGrNeg5QqiOqF96JEmgIgDbtjd5e3y3I8W/+ih2us3WtMxgnTXfqPd48i
VLcv28Q=
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBvzCCAUUCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
LmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABBk/Q+zMsZOJGkufRzGCWtSUtRjq
0QqChDGWbHLaa0h6ODVeEoKYOMvFJTg4V186tuuBe97KEey0OPDegzCBp5kBIiwg
HB/0xWoKdnfdRk6VyjmubPx399cGoZn8aCqgC6A/MD0GCSqGSIb3DQEJDjEwMC4w
LAYDVR0RBCUwI4IOY2xvdWRmbGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAoG
CCqGSM49BAMDA2gAMGUCMQC57VfwMXDyL5kM7vmO2ynbpgSAuFZT6Yd3C3NnV2jz
Biozw3eqIDXqCb2LI09stZMCMGIwCuVARr2IRctxf7AmX7/O2SIaIhCpMFKRedQ7
RiWGZIucp5r6AfT9381PB29bHA==
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICCjCCAWsCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
LmNvbTCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAHt/s9KTZETzu94JIAjZ3BaS
toSG65hGIc1e0Gt7PhdQxPp5FP2D8rQ1wc+pcZhD2O8525kPxopaqTd+fWKBuD3O
AULzoH2OX+atIuumTQzLNbTsIbP0tY3dh7d8LItuERkZn1NfsNl3z6bnNAaR137m
f4aWv49ImbA/Tkv8VmoKX279oD8wPQYJKoZIhvcNAQkOMTAwLjAsBgNVHREEJTAj
gg5jbG91ZGZsYXJlLmNvbYIRd3d3Y2xvdWRmbGFyZS5jb20wCgYIKoZIzj0EAwQD
gYwAMIGIAkIA8OX9LxWOVnyfB25DFBz6JkjhyDpBM/PXlgLnWb/n2mEuMMB44DOG
pljDV768PSW11AC3DtULoIyR92z0TyLEKYoCQgHdGd6PwUtDW5mrAMJQDgebjsxu
MwfcdthzKlFlSmRpHMBnRMOJjlg5f9CTBg9d6wEdv7ZIrQSO6eqQHDQRM0VMnw==
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIDCTCCAfMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTWdoYxX4KN51fP
WxQAyGH++VsPbfpAoXIbCPXSmU04BvIxyjzpHQ0ChMKkT/2VNcUeFJwk2fCf+ZwU
f0raTQTplofwkckE0gEYA3WcEfJp+hbvbTb/2recsf+JE6JACYJe2Uu5wsjtrE5j
A+7aT2BEU9RWzBdSy/5281ZfW3PArqcWaf8+RUyA3WRxVWmjmhFsVB+mdNLhCpW0
C0QNMYR1ppEZiKVnEdao8gcI5sOvSd+35t8g82aPXcNSPU6jKcx1YNUPX5wgPEmu
+anfc9RliQbYqqJYVODgBmV8IR5grw93yTsODoWKtFQ4PKVlnt9CD8AS/iSMQYm3
OUogqgMCAwEAAaA/MD0GCSqGSIb3DQEJDjEwMC4wLAYDVR0RBCUwI4IOY2xvdWRm
bGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAsGCSqGSIb3DQEBCwOCAQEAl809
gk9uZkRK+MJVYDSLjgGR2xqk5qOwnhovnispA7N3Z1GshodJRQa6ngNCKuXIm2/6
AxB9kDGK14n186Qq4odXqHSHs8FG9i0zUcBXeLv1rPAKtwKTas/SLmsOpPgWPZFa
iYiHHeu4HjOQoF987d7uGRYwc3xfstKwJsEXc12eCw2NH8TM1tJgSc/o6CzIpA91
QnZKhx6uGM4xI2gnOaJA1YikNhyFGBuOGMZgd0k2+/IcR2pg0z4pc5oQw1bXLANx
anqlA/MDrCM9v9019bRJ73zK8LQ3k/FW61PA9nL7RZ8ku65R+uYcVEdLa8pUeqnH
cJZNboDRsItpccZuRQ==
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIECTCCAnMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
LmNvbTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAL0zzgBv+VTwZOPy
LtuLFweQrj5Lfrje2hnNB7Y3TD4+yCM/cA4yTILixCe/B+N7LQysJgVDbW8u6BZQ
8ZqeDKOP6KCt37WhmcbT45tLpHmH+Z/uAnCz0hVc/7AyJ3CJXo6PaDCcJjgLuUun
W47iy4h79AxyuzELmUeZZGYcO8nqClqcnAzQ6sClGZvJwSbYg2QAFGoA2lHqZ9uN
ygAxNLd+rX9cP+yFwAeKzuKtOnVPiJD5lT3wufSkAbd6M7lOoqmTYnbv0A1WfA/e
upXno9lbgB6iwF5U0V7OtxdA1bTbvgJgNLlxFF1do0sB28CWmqCFNwLfzcPzt5A4
gLnOyLhNZOmUMXn35KOtp1Zv/yethlgZHxUYGcl6OYwMEFye3Du6dgnTwONzaLhA
7hMI8R60p2YrTLkgSKdFohAY/mKuxHyXxugOHHthlRCOn9m49edcdZ1HrkJXm9jd
P9katjCXgTwSdTQlvaMJkfH7wF3ZMjAxPcDf4RKFEpF2wABeNQIDAQABoD8wPQYJ
KoZIhvcNAQkOMTAwLjAsBgNVHREEJTAjgg5jbG91ZGZsYXJlLmNvbYIRd3d3Y2xv
dWRmbGFyZS5jb20wCwYJKoZIhvcNAQEMA4IBgQBF/RCHNAAOAaRI4VyO0tRPA5Dw
0/1/pgmBm/VejHIwDJnMFCl9njh0RSo1RgsVLhw6ovYbk3ORb4OD4UczPTq3GrFp
KP9uPR+2pR4FWJpCVfCl76YabQv6fUDdiT7ojzyRhsAmkd5rOdiMvWV3Rp+YmBuU
KH/dwkukfn+OeJIbERS5unzOBtQL+g5dU4CHWAqJQIqHr373w38OlYN+JY9QLrYy
sWU9Ye6RjdySXPJ5UzyfOEfc9Ji89RJsVeceB1+As5u5vBvtzGgIMSFUzN947RZo
DZ48JiB71VpmKXbn9LIRn25dlbVMzxRdSeZ194L3JFVAf9OxJTsc1QNFhOacoFgy
hqvtN2iKntEyPo2nacYhpz/FAdJ2JThNH+4WtpPWAqx8Lw/e1OttiDt+6M0FEuVz
svkSHnK206yo+a9Md37nUDDYxtlJEB+9F2qUZNQ7Hv+dxjmJOIgHOXxy1pLEdpVU
rGdGLVXeJNPCh9x+GK21QjdxZABmYAaF8k36Pv4=
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIFCTCCAvMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANkKL22jMn3eFCpj
T6lbeq4nC3aEqwTGrLARidAmO29WIhzs6LxRpM6xSMoPI6DvJVUGpMFEKF4xNTc5
X9/gSFrw2eI5Q3U3aGcaToSCxH4hXejwIzX8Ftlb/LfpXhbSsFr5MS3kiTY4zZxM
n3dSy2gZljD/g0tlQf5BdHdR4WKRhWnqRiGng+BmW4rjbcO7SoN33jSXsMcguCg5
8dmYuf5G5KVXsqwEoCQBeKGnca9orcm4i90VnGt4qZUpfAn1cADzYGpRzX79USJ6
tol4ovgGPN08LJFqcVl+dK8VzJ03JWBhI1jePbWS4Bz5oNtkhQQXilU+G6FQxc6a
UPf6KcFyOB+qMJmEwJZD9yaNK1YbsKfSztQEsb1JEezQnVHxp91Ch3AcWoikuOiY
yCg0V5lcK15SLv1+5sj9YzF7ngMmThcIJ6B5gS3swpD5AX6FJaI1BrGwT/RXKKQP
tRX1BySLx8RcINjFb5wv3q9QIE8vrW1BOk9f4dfmxiFYnc+6bCCbIrg7APQVtKTa
ixNJFSqZz7fm9loeNPHHXfUT5RoW5yzVa8igc+yv4qeYsWHcZ4c/Y91OJp19HMjM
bYm2alt8XagBgJjO0FW8wvsKwhhlhWK0WO6sQ7Fkl7fH1GtxEpc248hAW24SZMmS
led3LblCT8IC3a9BLhqJ2q8cfPp9AgMBAAGgPzA9BgkqhkiG9w0BCQ4xMDAuMCwG
A1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3d3djbG91ZGZsYXJlLmNvbTALBgkq
hkiG9w0BAQ0DggIBAAgz3NuN43+F+8+WhQ9hb7DOp6Amut7XubOkEBtBVgP3R8U1
uSsgocR1rvnZ1/bhkeGyTly0eQPhcSEdMo/GgIrcn+co0KLcDyV6Rf3Cgksx9dUZ
TzHSkxmFkxlxYfIGes6abH+2OPiacwK2gLvvmXFYIxEhv+LKzzteQi0xlinewv7R
FnSykZ4QialsFyCgOjOxa11aEdRv6T8qKwhjUOk0VedtzOkt/k95aydTNLjXl2OV
jloeTsbB00yWIqdyhG12+TgcJOa0pNP1zTjgFPodMuRUuiAcbT7Mt7sLCefKNzvZ
Ln6b4y7e6N3YLOHALTIP+LI4y8ar47WlXCNw/zeOM2sW8udjYrukN6WOV3X68oMf
Zsv6jqyGSaCDwdImR4VECUVvkabg9Sq4pz+ijTT+9cNA66omYL+/QAh0GahlROgW
kDGI8zeEUoAC8RkAbFGMJA8jEbAfbT000ZwnLX2SZ8YRQX4Jd1FTmAH99FkvvT8N
ovaGRSQQI5rWQGQYqF67So7PywEaEXeUHTBrv41Msva6CdaWHn7bh/fj4B21ETS7
VJvrk5DLJTyruqon7EVJU1pn38ppaXF4Z6a9n3C8TqudT/gdJUYn/SBo5jx20uGJ
d9k6vDqixntvk/TRZ848k1AXiv5uUJTdnoPPhzSGjxEaeKuB0R1ZHomVdjU4
-----END CERTIFICATE REQUEST-----

162
vendor/github.com/cloudflare/cfssl/log/log.go generated vendored Normal file
View File

@ -0,0 +1,162 @@
// Package log implements a wrapper around the Go standard library's
// logging package. Clients should set the current log level; only
// messages below that level will actually be logged. For example, if
// Level is set to LevelWarning, only log messages at the Warning,
// Error, and Critical levels will be logged.
package log
import (
"fmt"
"log"
"os"
)
// The following constants represent logging levels in increasing levels of seriousness.
const (
// LevelDebug is the log level for Debug statements.
LevelDebug = iota
// LevelInfo is the log level for Info statements.
LevelInfo
// LevelWarning is the log level for Warning statements.
LevelWarning
// LevelError is the log level for Error statements.
LevelError
// LevelCritical is the log level for Critical statements.
LevelCritical
// LevelFatal is the log level for Fatal statements.
LevelFatal
)
var levelPrefix = [...]string{
LevelDebug: "DEBUG",
LevelInfo: "INFO",
LevelWarning: "WARNING",
LevelError: "ERROR",
LevelCritical: "CRITICAL",
LevelFatal: "FATAL",
}
// Level stores the current logging level.
var Level = LevelInfo
// SyslogWriter specifies the necessary methods for an alternate output
// destination passed in via SetLogger.
//
// SyslogWriter is satisfied by *syslog.Writer.
type SyslogWriter interface {
Debug(string)
Info(string)
Warning(string)
Err(string)
Crit(string)
Emerg(string)
}
// syslogWriter stores the SetLogger() parameter.
var syslogWriter SyslogWriter
// SetLogger sets the output used for output by this package.
// A *syslog.Writer is a good choice for the logger parameter.
// Call with a nil parameter to revert to default behavior.
func SetLogger(logger SyslogWriter) {
syslogWriter = logger
}
func print(l int, msg string) {
if l >= Level {
if syslogWriter != nil {
switch l {
case LevelDebug:
syslogWriter.Debug(msg)
case LevelInfo:
syslogWriter.Info(msg)
case LevelWarning:
syslogWriter.Warning(msg)
case LevelError:
syslogWriter.Err(msg)
case LevelCritical:
syslogWriter.Crit(msg)
case LevelFatal:
syslogWriter.Emerg(msg)
}
} else {
log.Printf("[%s] %s", levelPrefix[l], msg)
}
}
}
func outputf(l int, format string, v []interface{}) {
print(l, fmt.Sprintf(format, v...))
}
func output(l int, v []interface{}) {
print(l, fmt.Sprint(v...))
}
// Fatalf logs a formatted message at the "fatal" level and then exits. The
// arguments are handled in the same manner as fmt.Printf.
func Fatalf(format string, v ...interface{}) {
outputf(LevelFatal, format, v)
os.Exit(1)
}
// Fatal logs its arguments at the "fatal" level and then exits.
func Fatal(v ...interface{}) {
output(LevelFatal, v)
os.Exit(1)
}
// Criticalf logs a formatted message at the "critical" level. The
// arguments are handled in the same manner as fmt.Printf.
func Criticalf(format string, v ...interface{}) {
outputf(LevelCritical, format, v)
}
// Critical logs its arguments at the "critical" level.
func Critical(v ...interface{}) {
output(LevelCritical, v)
}
// Errorf logs a formatted message at the "error" level. The arguments
// are handled in the same manner as fmt.Printf.
func Errorf(format string, v ...interface{}) {
outputf(LevelError, format, v)
}
// Error logs its arguments at the "error" level.
func Error(v ...interface{}) {
output(LevelError, v)
}
// Warningf logs a formatted message at the "warning" level. The
// arguments are handled in the same manner as fmt.Printf.
func Warningf(format string, v ...interface{}) {
outputf(LevelWarning, format, v)
}
// Warning logs its arguments at the "warning" level.
func Warning(v ...interface{}) {
output(LevelWarning, v)
}
// Infof logs a formatted message at the "info" level. The arguments
// are handled in the same manner as fmt.Printf.
func Infof(format string, v ...interface{}) {
outputf(LevelInfo, format, v)
}
// Info logs its arguments at the "info" level.
func Info(v ...interface{}) {
output(LevelInfo, v)
}
// Debugf logs a formatted message at the "debug" level. The arguments
// are handled in the same manner as fmt.Printf.
func Debugf(format string, v ...interface{}) {
outputf(LevelDebug, format, v)
}
// Debug logs its arguments at the "debug" level.
func Debug(v ...interface{}) {
output(LevelDebug, v)
}

186
vendor/github.com/cloudflare/cfssl/log/log_test.go generated vendored Normal file
View File

@ -0,0 +1,186 @@
package log
import (
"bytes"
"log"
"strings"
"testing"
)
const teststring = "asdf123"
func TestOutputf(t *testing.T) {
buf := new(bytes.Buffer)
log.SetOutput(buf)
Level = LevelDebug
outputf(LevelDebug, teststring, nil)
// outputf correctly prints string
if !strings.Contains(buf.String(), teststring) {
t.Fail()
}
return
}
func TestOutput(t *testing.T) {
buf := new(bytes.Buffer)
log.SetOutput(buf)
Level = LevelDebug
output(LevelDebug, nil)
// outputf correctly prints string with proper Debug prefix
if !strings.Contains(buf.String(), levelPrefix[LevelDebug]) {
t.Fail()
}
return
}
func TestCriticalf(t *testing.T) {
buf := new(bytes.Buffer)
log.SetOutput(buf)
Criticalf(teststring, nil)
// outputf correctly prints string
// should never fail because critical > debug
if !strings.Contains(buf.String(), teststring) {
t.Fail()
}
return
}
func TestCritical(t *testing.T) {
buf := new(bytes.Buffer)
log.SetOutput(buf)
Critical(nil)
// outputf correctly prints string
if !strings.Contains(buf.String(), levelPrefix[LevelCritical]) {
t.Fail()
}
return
}
func TestWarningf(t *testing.T) {
buf := new(bytes.Buffer)
log.SetOutput(buf)
Warningf(teststring, nil)
// outputf correctly prints string
// should never fail because fatal critical > debug
if !strings.Contains(buf.String(), teststring) {
t.Fail()
}
return
}
func TestWarning(t *testing.T) {
buf := new(bytes.Buffer)
log.SetOutput(buf)
Warning(nil)
// outputf correctly prints string
if !strings.Contains(buf.String(), levelPrefix[LevelWarning]) {
t.Fail()
}
return
}
func TestInfof(t *testing.T) {
buf := new(bytes.Buffer)
log.SetOutput(buf)
Infof(teststring, nil)
// outputf correctly prints string
// should never fail because fatal info > debug
if !strings.Contains(buf.String(), teststring) {
t.Fail()
}
return
}
func TestInfo(t *testing.T) {
buf := new(bytes.Buffer)
log.SetOutput(buf)
Info(nil)
// outputf correctly prints string
if !strings.Contains(buf.String(), levelPrefix[LevelInfo]) {
t.Fail()
}
return
}
func TestDebugf(t *testing.T) {
buf := new(bytes.Buffer)
log.SetOutput(buf)
Level = LevelDebug
Debugf(teststring, nil)
// outputf correctly prints string
// should never fail because fatal debug >= debug
if !strings.Contains(buf.String(), teststring) {
t.Fail()
}
return
}
func TestDebug(t *testing.T) {
buf := new(bytes.Buffer)
log.SetOutput(buf)
Level = LevelDebug
Debug(nil)
// outputf correctly prints string
if !strings.Contains(buf.String(), levelPrefix[LevelDebug]) {
t.Fail()
}
return
}
type testSyslogger struct {
*bytes.Buffer
}
func (l testSyslogger) Debug(s string) {
l.WriteString("[DEBUG] ")
_, _ = l.WriteString(s)
}
func (l testSyslogger) Info(s string) {
l.WriteString("[INFO] ")
_, _ = l.WriteString(s)
}
func (l testSyslogger) Warning(s string) {
l.WriteString("[WARN] ")
_, _ = l.WriteString(s)
}
func (l testSyslogger) Err(s string) {
l.WriteString("[ERROR] ")
_, _ = l.WriteString(s)
}
func (l testSyslogger) Crit(s string) {
l.WriteString("[CRIT] ")
_, _ = l.WriteString(s)
}
func (l testSyslogger) Emerg(s string) {
l.WriteString("[FATAL] ")
_, _ = l.WriteString(s)
}
func TestSetLogger(t *testing.T) {
buf := new(bytes.Buffer)
SetLogger(testSyslogger{buf})
Level = LevelDebug
outputf(LevelDebug, teststring, nil)
// outputf correctly prints string
if !strings.Contains(buf.String(), teststring) {
t.Fail()
}
SetLogger(nil)
return
}

View File

@ -0,0 +1,13 @@
// Package config in the ocsp directory provides configuration data for an OCSP
// signer.
package config
import "time"
// Config contains configuration information required to set up an OCSP signer.
type Config struct {
CACertFile string
ResponderCertFile string
KeyFile string
Interval time.Duration
}

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAvKOCXwP8Y6x1YkjcimQafnP1bRCF/iWY+z4ffuTWA150RRpA
GnhwOen8muU5wxOEm1A2IkWhNfXQ9GYVdOnzXumTx9Go4Gm8/1nRCYG69GZbQAEr
pNGx/l4wReLVj2iizCf/xkcch5ZM/5zplXWZXCQiavmKz6M+1aSYdsGP0mrLu31c
yod2iJmlISt+nuP5yXkgoKxzGrKjP5qrs6XniVXrKMt+5g1Ta5blWUoft2pwM6yp
8+IAtxh+iYTIJc8dDHbVl9AjVfsfaYeS8SkHcIRyIuD8/3HgLmP/gMLDzuLXvH+W
slOEYqLGMkSo2JPOwLguggDyjt1rI2cEcFkgJwIDAQABAoIBAQCTAZW6+D87ag28
f22nR+XBwBp2WVcivSggO8SNvkXuMDDKHW/xcQR8jZW3HIZMOSyxYOwe/0Zn595k
aB22lA9+Wuc45HIIGT8ZfGREVV5d0lqwYXkio+xjgAF8pQ6rCO89zLouSgK4w2/U
D/OU7yWJwfs0hK4hrGVuVywd+DBd2Fc7UfZ4oEcy89mwUIRVK8+eXrRCav6lGDrz
I+GmW6GL16U8lS8vsUNciYyNYCzgSIIa/yyiZO/Aje93yJRVpmujAK2p6/w/7vmK
OareeixlpNYpiY7Nk6o3w6sKEEVzf+AquDgeH5IkzD1nkYbd+JY7bdg1cgjz3kJg
IhsiIER5AoGBAOkZpicTIsiAMxz43bzMt1IMYu1ezAEw4Vk2sVEbSfFXdbO5J9gW
/Ou+AhwxhsDeO6vgh3mYkG+2s5U+ztk68X1BVIf87kYBQiz175XvxcLmDBFm5S6g
eyTCwsop9J4XlgQQ5HNm80G9oHnF50oujCqpUiC5xj5fEd8vULmua5jTAoGBAM8r
rTTpVBHKArDlzYF5EpyXDkcFT2uAgw9Xpc6xIl/UWQ+XU1qD5Te0fmjpdwo3VZTL
W2e8eg0U9O2skrxBcRLREnh1U2znCMSIGTkwYQ2JDjhz2Jjbh8r/NhvSdydql9wQ
LGyPOIpcURaD+ohOExF82EtEqWgNp4QfQHH70cbdAoGAPBoy7yxN8aishTHd6opW
Uj+DWnTw4PW7hQdHHQSOQj4syRRao6r5t8ccQCy89AnZFO4lwEKIK2XOVBMHvpcm
IQexRgb/YOl+KJ2ZEu3p7eDnB62iNi2G0ums0/eRbRnjwlSgsui+nBrKv9s5UbVC
ytUxqeJ8rSRSNVu70sSYVaUCgYALYUrSbT7A+2fKb9UqF4x+LY4LOK90KEsKvLXO
9Mv+l5uMz7M0dapRtQh8mtZ/KSr6UXFj8WaC8XPC2of072NWtUVeeJNsmARTR2ab
TZ0HMVAmqbZsLyL2c651OMpyz9gnrnvCOtvQPeH2aqmIc0F45HK9L7hejuF00IKp
wDt1wQKBgQC8sjlF/8e03m3AfLs2ZW/w0Rsggz52TgBdH24BMUmvd5McVZlH8uZq
zwx5ht3ppVjObG28JPEj8c/FtAmsUjURDD7EVdjb5bDxrMtH++8sHrXUuMMBeUxl
DN2IU+xL9MwMh5H0cyJbXnE+LWGpSefCccDnH5qlEjwNXE5/RggOrw==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDvjCCAqigAwIBAgIIWhorb65IXvUwCwYJKoZIhvcNAQELMG0xCzAJBgNVBAYT
AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu
ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y
bmlhMB4XDTE1MDQxOTE2MTAwMFoXDTIwMDQxNzE2MTAwMFowbTELMAkGA1UEBhMC
VVMxEzARBgNVBAoTCkNsb3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5l
ZXJpbmcxFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3Ju
aWEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8o4JfA/xjrHViSNyK
ZBp+c/VtEIX+JZj7Ph9+5NYDXnRFGkAaeHA56fya5TnDE4SbUDYiRaE19dD0ZhV0
6fNe6ZPH0ajgabz/WdEJgbr0ZltAASuk0bH+XjBF4tWPaKLMJ//GRxyHlkz/nOmV
dZlcJCJq+YrPoz7VpJh2wY/Sasu7fVzKh3aImaUhK36e4/nJeSCgrHMasqM/mquz
peeJVesoy37mDVNrluVZSh+3anAzrKnz4gC3GH6JhMglzx0MdtWX0CNV+x9ph5Lx
KQdwhHIi4Pz/ceAuY/+AwsPO4te8f5ayU4RiosYyRKjYk87AuC6CAPKO3WsjZwRw
WSAnAgMBAAGjZjBkMA4GA1UdDwEB/wQEAwIABjASBgNVHRMBAf8ECDAGAQH/AgEC
MB0GA1UdDgQWBBSrzjPP4Y5PLsqeyp6iddofBjoRmTAfBgNVHSMEGDAWgBSrzjPP
4Y5PLsqeyp6iddofBjoRmTALBgkqhkiG9w0BAQsDggEBAH7McpSm7+DeIZPQKYpF
kFUlNn3N4MRvek5lxOw6jLE1QmzG3lTB79g6iBiGKsYLPoJqNS6VxMoLrMC+qFhM
0QM5eIzRpdfYa83IDIYcbUYx7fLG/azX+FMFh/O5yPtS+bqbxGinxofRIyuKGs9r
dks6I5lGncRs0Liysp4mHJAjyj9G2W2onI3Y00BYhiOy4mYvZ5/S31KI4550HZ+p
dnexuC29CsWGkOTXTOS7+e7Zmbh8UjsYcA5YOojew+EjJfETPVO+Pn7WGg/+XrFX
8UOG3o9k8M0ePQof4R6FTJ+BQxtSkWWdp1HrMQbZ1TXfZx84XkmFdcmy8FjYiHbP
M+M=
-----END CERTIFICATE-----

View File

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID4TCCAsugAwIBAgIIEoDcqfKl/s4wCwYJKoZIhvcNAQELMG0xCzAJBgNVBAYT
AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu
ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y
bmlhMB4XDTE1MDQxOTE2MTkwMFoXDTE2MDQxODE2MTkwMFowXTELMAkGA1UEBhMC
VVMxEDAOBgNVBAoTB0V4YW1wbGUxDzANBgNVBAsTBlRoaW5nczEWMBQGA1UEBxMN
U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAK7jUnRUeD5QY9YPjbW6aiGkVWRWAebi4nZl++C+
HEBHSyB0jXX+J93y97PuhgeguCuMM6KZU7C0tPZKjwdxBSqpXeyFpvcj+UWMjZjz
9FrBAzZ1DIYquqfYuKUtavoFv29IomRqzyZ4FrMJ2qy0RudnWMTqn4P6/7DrWos+
oJMCpl/mdWl+YXMXypgW5JwM7ladx8GkEKQwGMtXrG9pop7qS6LNikN76tLPYWjR
DhrWLBe8gCGjuXkwvxw78CeeJNyWF+P/+x4lVsWphip3jX57SUx/bjaRjsWSfpMz
xHueHtuCrGffgCkFzYH1/Z60FZNxuHYqJeL4V3gcR8IIaZECAwEAAaOBmDCBlTAO
BgNVHQ8BAf8EBAMCAKAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG
A1UdEwEB/wQCMAAwHQYDVR0OBBYEFBnFrxc1gkG2CYImTYKL0DAaGxRBMB8GA1Ud
IwQYMBaAFKvOM8/hjk8uyp7KnqJ12h8GOhGZMBYGA1UdEQQPMA2CC2V4YW1wbGUu
Y29tMAsGCSqGSIb3DQEBCwOCAQEAX31Jk7R9gDMw/gepIxxeKx9m+c7eOYDxjJ12
bfXQVKNNPLZsO9M9r2/0BCTFsNTF2jh6ZTeIf7qy+Jw08YqTcO5m8jhiGzCjOYu5
tiGxCUe+cYjXcCRk83+XGkVrQm3fQ0cVtic0yfm/fez3iv915jH0GYO5X8/d7bKa
0kWJ3uOjur6tenfnisypEsuYYjPRcQdXSG6/qgHEc4r279Z2ltjy1bFFr86hHUbj
DX7XNWH/MXFgqLzfQm5VzmqBj9om+0/tgTWdkgI1DK/Hnvm9A4YZfaxh4fxv7ITo
Ce8FWW13Wj55x64peb8ZiW1jUyoaJQcxQxFpRHIVu26nXApWtg==
-----END CERTIFICATE-----

View File

@ -0,0 +1 @@
{"driver":"sqlite3","data_source":"sqlite_test.db"}

View File

@ -0,0 +1,2 @@
MIIFCAoBAKCCBQEwggT9BgkrBgEFBQcwAQEEggTuMIIE6jCBrKADAgEAoS0wKzEpMCcGA1UEAwwgY2Fja2xpbmcgY3J5cHRvZ3JhcGhlciBmYWtlIFJPT1QYDzIwMTUxMDIxMjEyNjAwWjBlMGMwOzAJBgUrDgMCGgUABBSwLsMRhyg1dJUwnXWk++D57lvgagQU6aQ/7p6l5vLV13lgPJOmLiSOl6oCAhJNgAAYDzIwMTUwOTAxMDAwMDAwWqARGA8yMDE0MDEwMTAwMDAwMFowDQYJKoZIhvcNAQELBQADggEBAHlFcNKa7mZDJeWzJt1S45kx4gDqOLzyeZzflFbSjsrHRrLA7Y3RKoy0i4Y9Vi6Jfhe7xj6dgDMJy1Z1qayI/Q8QvnaU6V2kFcnaD7pah9uALu2xNYMJPllq8KsQYvDLa1E2PMvQTqDhY2/QrIuxw3jkqtzeI5aG0idFm3aF1z/v3dt6XPWjE8IlAJfXY4CeUorLvA+mK2YHJ3V7MSgymVXZdyth1rg0/0cP9v77Rlb8hmWA/EUMcIPKQqErVQK+gZiVC0SfElaMO25CD9cjY+fd904oC5+ahvhHXxOSEbXVZBT1FY2teFCKEpx86gAVcZWpGmVwJO+dpsrkgwpN786gggMjMIIDHzCCAxswggIDoAMCAQICCQDNMc/iNkPNdTANBgkqhkiG9w0BAQsFADArMSkwJwYDVQQDDCBjYWNrbGluZyBjcnlwdG9ncmFwaGVyIGZha2UgUk9PVDAeFw0xNTEwMjEyMDExNTJaFw0yMDEwMTkyMDExNTJaMCsxKTAnBgNVBAMMIGNhY2tsaW5nIGNyeXB0b2dyYXBoZXIgZmFrZSBST09UMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+TbvalHXQYO6GhJUJZI5mF2k4+nZDIvqWyrjw+2k9+UAcekuLKPpSclu9aBRvUggw3XFHAW95qW6Dv2+5gvinUmTq9Ry7kVTUYAxyZu1ydHt+wDETmFJfeY6/fpBHHIsuGLItqpUGmr8D6LROGEqfFY2B9+08O7Zs+FufDRgLHWEvLTdpPkrzeDJs9Oo6g38jfT9b4+9Ahs+FvvwqneAkbeZgBC2NWKB+drMuNBTPbF/W1a8czAzHeOs6qy0dBlTHNjL62/o9cRKNiKe3IqwHJdd01V1aLSUgIbe2HrP9EC1djnUXWR3jx3ursaKt7PTKsC52UJkRqnai80MzQj0WwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU6aQ/7p6l5vLV13lgPJOmLiSOl6owDQYJKoZIhvcNAQELBQADggEBACuwILDTvaBrdorv2zMsYnZuKvXtknWAf/DTcvF4N5PMOPBNkeHuGfv0VDe6VXpBHiU5G9E2RdU435W7o0kRSn27YcqrxaXGt9m2kArW6e49136+MnFx47jjk0p4T48s6MeaL5JVLJzxYouu1ZOZqlVokwNPO+8bxn6ALumIVUOD1jSBN7Y9pgLUS2rzO5pe5pxS2Ak/eO7Q7M21r1sEuG/uPuWqBFogk+4Z9omKVZdRDbzm9vYUATgEZdlTe2tct3BVBQ2zWbe0R2svIuCs8XzERykvfv1JawxI68I9vN0Dh9vj/xDM6udorfALlhjgQdftmbHovRLpJ1ZSOMIUNGY=
MIIFCAoBAKCCBQEwggT9BgkrBgEFBQcwAQEEggTuMIIE6jCBrKADAgEAoS0wKzEpMCcGA1UEAwwgY2Fja2xpbmcgY3J5cHRvZ3JhcGhlciBmYWtlIFJPT1QYDzIwMTUxMDIxMjA1NTAwWjBlMGMwOzAJBgUrDgMCGgUABBSwLsMRhyg1dJUwnXWk++D57lvgagQU6aQ/7p6l5vLV13lgPJOmLiSOl6oCAhJNgAAYDzIwMTUxMDIwMDAwMDAwWqARGA8yMDMwMTAyMDAwMDAwMFowDQYJKoZIhvcNAQELBQADggEBAFgnZ/Ft1LTDYPwPlecOtLykgwS4HZTelUaSi841nq/tgfLM11G3D1AUXAT2V2jxiG+0YTxzkWd5v44KJGB9Mm+qjafPMKR3ULjQkJHJ8goFHpWkUtLrIYurj8N+4HpwZ+RJccieuZIX8SMeSWRq5w83okWZPGoUrl6GRdQDteE7imrNkBa35zrzUWozPqY8k90ttKfhZHRXNCJe8YbVfJRDh0vVZABzlfHeW8V+ie15HPVDx/M341KC3tBMM88e5/bt3sLyUU8SwxGH5nOe/ohVpjhkjk2Pz4TPdwD2ZK5Auc09VBfivdLYRE84BMhd8/yOEt53VWGPIMxWUVtrUyegggMjMIIDHzCCAxswggIDoAMCAQICCQDNMc/iNkPNdTANBgkqhkiG9w0BAQsFADArMSkwJwYDVQQDDCBjYWNrbGluZyBjcnlwdG9ncmFwaGVyIGZha2UgUk9PVDAeFw0xNTEwMjEyMDExNTJaFw0yMDEwMTkyMDExNTJaMCsxKTAnBgNVBAMMIGNhY2tsaW5nIGNyeXB0b2dyYXBoZXIgZmFrZSBST09UMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+TbvalHXQYO6GhJUJZI5mF2k4+nZDIvqWyrjw+2k9+UAcekuLKPpSclu9aBRvUggw3XFHAW95qW6Dv2+5gvinUmTq9Ry7kVTUYAxyZu1ydHt+wDETmFJfeY6/fpBHHIsuGLItqpUGmr8D6LROGEqfFY2B9+08O7Zs+FufDRgLHWEvLTdpPkrzeDJs9Oo6g38jfT9b4+9Ahs+FvvwqneAkbeZgBC2NWKB+drMuNBTPbF/W1a8czAzHeOs6qy0dBlTHNjL62/o9cRKNiKe3IqwHJdd01V1aLSUgIbe2HrP9EC1djnUXWR3jx3ursaKt7PTKsC52UJkRqnai80MzQj0WwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU6aQ/7p6l5vLV13lgPJOmLiSOl6owDQYJKoZIhvcNAQELBQADggEBACuwILDTvaBrdorv2zMsYnZuKvXtknWAf/DTcvF4N5PMOPBNkeHuGfv0VDe6VXpBHiU5G9E2RdU435W7o0kRSn27YcqrxaXGt9m2kArW6e49136+MnFx47jjk0p4T48s6MeaL5JVLJzxYouu1ZOZqlVokwNPO+8bxn6ALumIVUOD1jSBN7Y9pgLUS2rzO5pe5pxS2Ak/eO7Q7M21r1sEuG/uPuWqBFogk+4Z9omKVZdRDbzm9vYUATgEZdlTe2tct3BVBQ2zWbe0R2svIuCs8XzERykvfv1JawxI68I9vN0Dh9vj/xDM6udorfALlhjgQdftmbHovRLpJ1ZSOMIUNGY=

Binary file not shown.

View File

@ -0,0 +1 @@
MIICGAoBAKCCAhEwggINBgkrBgEFBQcwAQEEggH+OZ4ZSKS2J85Kr9UaI2LAEFKvOM8/hjk8uyp7KnqJ12h8GOhGZAgIBdaADAQH/GA8wMDAxMDEwMTAwMDAwMFqgERgPMDAwMTAxMDEwMDAwMDBaMA0GCSqGSIb3DQEBCwUAA4IBAQCBGs+8UNwUdkEBladnajZIV+sHtmao/mMTIvpyPqnmV2Ab9KfNWlSDSDuMtZYKS4VsEwtbZ+4kKWI8DugE6egjP3o64R7VP2aqrh41IORwccLGVsexILBpxg4h602JbhXM0sxgXoh5WAt9f1oy6PsHAt/XAuJGSo7yMNv3nHKNFwjExmZt21sNLYlWlljjtX92rlo/mBTWKO0js4YRNyeNQhchARbn9oL18jW0yAVqB9a8rees+EippbTfoktFf0cIhnmkiknPZSZ+dN2qHkxiXIujWlymZzUZcqRTNtrmmhlOdt35QSg7Vw8eyw2rl8ZU94zaI5DPWn1QYn0dk7l9

Binary file not shown.

View File

@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIICATCCAWoCCQDidF+uNJR6czANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMB4XDTEyMDUwMTIyNTUxN1oXDTEzMDUwMTIyNTUxN1owRTELMAkG
A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl
nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj
w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81
KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF
AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp
iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt
+LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw==
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC2mOWeh2HPfWQsQmh4tKRGau/yXt7GQa07RES0huKuP0EHLrhl
dUETuSEoY7ZyczxTvKPDs21+H4i8KNlUDd3ZeodLc+Ou3geZT9wYI40Tz40Reip3
MtQM86LHWoMNEG9ezzUoBXaqHoJgdlt2qLGEN6uO8lwPg2x3uQTERl8e4QIDAQAB
AoGAVxnsPojZ8X4g8LPk3d9dlXGhb/4tSmk9102jcHH/Y5ssy95Pe6ZJGr1uwbN+
7m1l05PikpHeoxEryoW51cyfjDVkXUT0zPp2JC38DUA/0A8qWav/aENM64wg1I0P
Dil8FywzZEonRNJst53+9cxFye70ely5br/tWxEp4/MsM1kCQQDqV4Lwn8BXOeKg
xOwNmcL+0XPedvSPBSPUoGJCzu12rH6Z+UHXipXsqRNSyQ+KGlur14y0kCh5uiVA
jmWYVEEjAkEAx3keAo1nFsVW35EPt5LIbh6L6ty7GrvGRvOVeSd6YLtixMety24k
hpt1cEv2xlFnbjbBbMkr9eUiUNpttLT6KwJBANGKaLoSjqEwUFYjX1OV/wdtcGcn
BOzx0qUouFQ2xZ0NBrNVbyt1bzPLx0yKHkwF35ybw+Qc1yRpby/3ZB6+j/MCQFLl
vtcItOL9uBDJVGLSGYHKKBO/D/MYPlqWOHRVN8KjnXRyF4QHjh5y1OeKalAY3Ict
Mk1nfWF/jDdVz2neHGkCQHHBR4Xt1/euDku+14z5aLpphTEQVuRD2vQoeKi/W/CY
OgNmKj1DzucnCS6yRCrF8Q0Pn8l054a3Wdbl1gqI/gA=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,9 @@
-----BEGIN CERTIFICATE-----
IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl
nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj
w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81
KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF
AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp
iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt
+LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw==
-----END CERTIFICATE-----

View File

@ -0,0 +1,8 @@
-----BEGIN RSA PRIVATE KEY-----
jmWYVEEjAkEAx3keAo1nFsVW35EPt5LIbh6L6ty7GrvGRvOVeSd6YLtixMety24k
hpt1cEv2xlFnbjbBbMkr9eUiUNpttLT6KwJBANGKaLoSjqEwUFYjX1OV/wdtcGcn
BOzx0qUouFQ2xZ0NBrNVbyt1bzPLx0yKHkwF35ybw+Qc1yRpby/3ZB6+j/MCQFLl
vtcItOL9uBDJVGLSGYHKKBO/D/MYPlqWOHRVN8KjnXRyF4QHjh5y1OeKalAY3Ict
Mk1nfWF/jDdVz2neHGkCQHHBR4Xt1/euDku+14z5aLpphTEQVuRD2vQoeKi/W/CY
OgNmKj1DzucnCS6yRCrF8Q0Pn8l054a3Wdbl1gqI/gA=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDqjCCApKgAwIBAgIUFqT7NscPhQ5kfZTYNhWTKXVekrswDQYJKoZIhvcNAQEL
BQAwbTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMQ8wDQYDVQQHEwZJ
dGhhY2ExLDAqBgNVBAoTI1RoZSBCZXN0IE9wZW4tU291cmNlIEhhY2thdGhvbiBU
ZWFtMQwwCgYDVQQLEwNXV1cwHhcNMTcwMjExMTQxMDAwWhcNMjIwMjEwMTQxMDAw
WjBtMQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxDzANBgNVBAcTBkl0
aGFjYTEsMCoGA1UEChMjVGhlIEJlc3QgT3Blbi1Tb3VyY2UgSGFja2F0aG9uIFRl
YW0xDDAKBgNVBAsTA1dXVzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ANR66Ky8dBV2FVyDOGXFM4bF63EJxI7PgCKg8yiJsYihwo5wsABpiI66offWsJNV
rRKT8QhGohm4V1B/MOpdb3slOYVFXAInjoKyClPYDK3GMkJ8mo6mFysm3q/JqlEl
KjvVIb8Yq7cgPAj/MOb4rBJu5+c3sM37CwpUbxCTdPiuVMGYDjVKauloJfTir0HQ
RMwREsO6fyzSia4qvfj4ljWGzPtEVrRmzs7LguLr3DkUjXMSq7AI3L+oUdiYR6kV
c3rLucMQKRCNGMcU3T8Sq9Pwt2sUeAFNqcXk9E1FqesYwFoEejStU24wpTd4ah0g
tL1LyoEYG6etUehrxlRlMJsCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFANQ4+9iVQzAZdHhb0fNXtrb3krdMA0GCSqG
SIb3DQEBCwUAA4IBAQA4SKVpdJj40xaeyVkHWtrY4O8wB2J7Z6rsUf9jlEySeQaH
GWI4LUOKjrU0u/NtuvTybDHyfc1VrdgZmfaukE35VyQ1+xWa/47Q7KISSCH1x0cF
L+WdJqKHD0q/tR2uz/fw9AUlV1LkBEeAZclhPxCLv32gLExQrNCBVa7c9Xkq1muB
o0ootJF9sTZopqnsMldvMBWOl/9cb2dxPKu3AcNpCm28wt+rwqHIu+Fna9Fe/n+y
SmWTaP3l/eiLskFUvmHKSUVwTEPC6kbK9rxKPz7ijQ3h/YuWxxz32L2CpsOfekgT
7jER0Y/xxZq7XykdwZ1VKKfZGnsH8mU2rU335Gd1
-----END CERTIFICATE-----

Binary file not shown.

View File

@ -0,0 +1,556 @@
// Package local implements certificate signature functionality for CFSSL.
package local
import (
"bytes"
"crypto"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/hex"
"encoding/pem"
"errors"
"io"
"math/big"
"net"
"net/http"
"net/mail"
"os"
"github.com/cloudflare/cfssl/certdb"
"github.com/cloudflare/cfssl/config"
cferr "github.com/cloudflare/cfssl/errors"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/info"
"github.com/cloudflare/cfssl/log"
"github.com/cloudflare/cfssl/signer"
"github.com/google/certificate-transparency-go"
"github.com/google/certificate-transparency-go/client"
"github.com/google/certificate-transparency-go/jsonclient"
"golang.org/x/net/context"
)
// Signer contains a signer that uses the standard library to
// support both ECDSA and RSA CA keys.
type Signer struct {
ca *x509.Certificate
priv crypto.Signer
policy *config.Signing
sigAlgo x509.SignatureAlgorithm
dbAccessor certdb.Accessor
}
// NewSigner creates a new Signer directly from a
// private key and certificate, with optional policy.
func NewSigner(priv crypto.Signer, cert *x509.Certificate, sigAlgo x509.SignatureAlgorithm, policy *config.Signing) (*Signer, error) {
if policy == nil {
policy = &config.Signing{
Profiles: map[string]*config.SigningProfile{},
Default: config.DefaultConfig()}
}
if !policy.Valid() {
return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
}
return &Signer{
ca: cert,
priv: priv,
sigAlgo: sigAlgo,
policy: policy,
}, nil
}
// NewSignerFromFile generates a new local signer from a caFile
// and a caKey file, both PEM encoded.
func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signer, error) {
log.Debug("Loading CA: ", caFile)
ca, err := helpers.ReadBytes(caFile)
if err != nil {
return nil, err
}
log.Debug("Loading CA key: ", caKeyFile)
cakey, err := helpers.ReadBytes(caKeyFile)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
}
parsedCa, err := helpers.ParseCertificatePEM(ca)
if err != nil {
return nil, err
}
strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD")
password := []byte(strPassword)
if strPassword == "" {
password = nil
}
priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password)
if err != nil {
log.Debug("Malformed private key %v", err)
return nil, err
}
return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
}
func (s *Signer) sign(template *x509.Certificate) (cert []byte, err error) {
var initRoot bool
if s.ca == nil {
if !template.IsCA {
err = cferr.New(cferr.PolicyError, cferr.InvalidRequest)
return
}
template.DNSNames = nil
template.EmailAddresses = nil
s.ca = template
initRoot = true
}
derBytes, err := x509.CreateCertificate(rand.Reader, template, s.ca, template.PublicKey, s.priv)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err)
}
if initRoot {
s.ca, err = x509.ParseCertificate(derBytes)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
}
}
cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
log.Infof("signed certificate with serial number %d", template.SerialNumber)
return
}
// replaceSliceIfEmpty replaces the contents of replaced with newContents if
// the slice referenced by replaced is empty
func replaceSliceIfEmpty(replaced, newContents *[]string) {
if len(*replaced) == 0 {
*replaced = *newContents
}
}
// PopulateSubjectFromCSR has functionality similar to Name, except
// it fills the fields of the resulting pkix.Name with req's if the
// subject's corresponding fields are empty
func PopulateSubjectFromCSR(s *signer.Subject, req pkix.Name) pkix.Name {
// if no subject, use req
if s == nil {
return req
}
name := s.Name()
if name.CommonName == "" {
name.CommonName = req.CommonName
}
replaceSliceIfEmpty(&name.Country, &req.Country)
replaceSliceIfEmpty(&name.Province, &req.Province)
replaceSliceIfEmpty(&name.Locality, &req.Locality)
replaceSliceIfEmpty(&name.Organization, &req.Organization)
replaceSliceIfEmpty(&name.OrganizationalUnit, &req.OrganizationalUnit)
if name.SerialNumber == "" {
name.SerialNumber = req.SerialNumber
}
return name
}
// OverrideHosts fills template's IPAddresses, EmailAddresses, and DNSNames with the
// content of hosts, if it is not nil.
func OverrideHosts(template *x509.Certificate, hosts []string) {
if hosts != nil {
template.IPAddresses = []net.IP{}
template.EmailAddresses = []string{}
template.DNSNames = []string{}
}
for i := range hosts {
if ip := net.ParseIP(hosts[i]); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else if email, err := mail.ParseAddress(hosts[i]); err == nil && email != nil {
template.EmailAddresses = append(template.EmailAddresses, email.Address)
} else {
template.DNSNames = append(template.DNSNames, hosts[i])
}
}
}
// Sign signs a new certificate based on the PEM-encoded client
// certificate or certificate request with the signing profile,
// specified by profileName.
func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
profile, err := signer.Profile(s, req.Profile)
if err != nil {
return
}
block, _ := pem.Decode([]byte(req.Request))
if block == nil {
return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed)
}
if block.Type != "NEW CERTIFICATE REQUEST" && block.Type != "CERTIFICATE REQUEST" {
return nil, cferr.Wrap(cferr.CSRError,
cferr.BadRequest, errors.New("not a csr"))
}
csrTemplate, err := signer.ParseCertificateRequest(s, block.Bytes)
if err != nil {
return nil, err
}
// Copy out only the fields from the CSR authorized by policy.
safeTemplate := x509.Certificate{}
// If the profile contains no explicit whitelist, assume that all fields
// should be copied from the CSR.
if profile.CSRWhitelist == nil {
safeTemplate = *csrTemplate
} else {
if profile.CSRWhitelist.Subject {
safeTemplate.Subject = csrTemplate.Subject
}
if profile.CSRWhitelist.PublicKeyAlgorithm {
safeTemplate.PublicKeyAlgorithm = csrTemplate.PublicKeyAlgorithm
}
if profile.CSRWhitelist.PublicKey {
safeTemplate.PublicKey = csrTemplate.PublicKey
}
if profile.CSRWhitelist.SignatureAlgorithm {
safeTemplate.SignatureAlgorithm = csrTemplate.SignatureAlgorithm
}
if profile.CSRWhitelist.DNSNames {
safeTemplate.DNSNames = csrTemplate.DNSNames
}
if profile.CSRWhitelist.IPAddresses {
safeTemplate.IPAddresses = csrTemplate.IPAddresses
}
if profile.CSRWhitelist.EmailAddresses {
safeTemplate.EmailAddresses = csrTemplate.EmailAddresses
}
}
if req.CRLOverride != "" {
safeTemplate.CRLDistributionPoints = []string{req.CRLOverride}
}
if safeTemplate.IsCA {
if !profile.CAConstraint.IsCA {
log.Error("local signer policy disallows issuing CA certificate")
return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
}
if s.ca != nil && s.ca.MaxPathLen > 0 {
if safeTemplate.MaxPathLen >= s.ca.MaxPathLen {
log.Error("local signer certificate disallows CA MaxPathLen extending")
// do not sign a cert with pathlen > current
return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
}
} else if s.ca != nil && s.ca.MaxPathLen == 0 && s.ca.MaxPathLenZero {
log.Error("local signer certificate disallows issuing CA certificate")
// signer has pathlen of 0, do not sign more intermediate CAs
return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
}
}
OverrideHosts(&safeTemplate, req.Hosts)
safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject)
// If there is a whitelist, ensure that both the Common Name and SAN DNSNames match
if profile.NameWhitelist != nil {
if safeTemplate.Subject.CommonName != "" {
if profile.NameWhitelist.Find([]byte(safeTemplate.Subject.CommonName)) == nil {
return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
}
}
for _, name := range safeTemplate.DNSNames {
if profile.NameWhitelist.Find([]byte(name)) == nil {
return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
}
}
for _, name := range safeTemplate.EmailAddresses {
if profile.NameWhitelist.Find([]byte(name)) == nil {
return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
}
}
}
if profile.ClientProvidesSerialNumbers {
if req.Serial == nil {
return nil, cferr.New(cferr.CertificateError, cferr.MissingSerial)
}
safeTemplate.SerialNumber = req.Serial
} else {
// RFC 5280 4.1.2.2:
// Certificate users MUST be able to handle serialNumber
// values up to 20 octets. Conforming CAs MUST NOT use
// serialNumber values longer than 20 octets.
//
// If CFSSL is providing the serial numbers, it makes
// sense to use the max supported size.
serialNumber := make([]byte, 20)
_, err = io.ReadFull(rand.Reader, serialNumber)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err)
}
// SetBytes interprets buf as the bytes of a big-endian
// unsigned integer. The leading byte should be masked
// off to ensure it isn't negative.
serialNumber[0] &= 0x7F
safeTemplate.SerialNumber = new(big.Int).SetBytes(serialNumber)
}
if len(req.Extensions) > 0 {
for _, ext := range req.Extensions {
oid := asn1.ObjectIdentifier(ext.ID)
if !profile.ExtensionWhitelist[oid.String()] {
return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
}
rawValue, err := hex.DecodeString(ext.Value)
if err != nil {
return nil, cferr.Wrap(cferr.CertificateError, cferr.InvalidRequest, err)
}
safeTemplate.ExtraExtensions = append(safeTemplate.ExtraExtensions, pkix.Extension{
Id: oid,
Critical: ext.Critical,
Value: rawValue,
})
}
}
var distPoints = safeTemplate.CRLDistributionPoints
err = signer.FillTemplate(&safeTemplate, s.policy.Default, profile, req.NotBefore, req.NotAfter)
if err != nil {
return nil, err
}
if distPoints != nil && len(distPoints) > 0 {
safeTemplate.CRLDistributionPoints = distPoints
}
var certTBS = safeTemplate
if len(profile.CTLogServers) > 0 || req.ReturnPrecert {
// Add a poison extension which prevents validation
var poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}}
var poisonedPreCert = certTBS
poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension)
cert, err = s.sign(&poisonedPreCert)
if err != nil {
return
}
if req.ReturnPrecert {
return cert, nil
}
derCert, _ := pem.Decode(cert)
prechain := []ct.ASN1Cert{{Data: derCert.Bytes}, {Data: s.ca.Raw}}
var sctList []ct.SignedCertificateTimestamp
for _, server := range profile.CTLogServers {
log.Infof("submitting poisoned precertificate to %s", server)
ctclient, err := client.New(server, nil, jsonclient.Options{})
if err != nil {
return nil, cferr.Wrap(cferr.CTError, cferr.PrecertSubmissionFailed, err)
}
var resp *ct.SignedCertificateTimestamp
ctx := context.Background()
resp, err = ctclient.AddPreChain(ctx, prechain)
if err != nil {
return nil, cferr.Wrap(cferr.CTError, cferr.PrecertSubmissionFailed, err)
}
sctList = append(sctList, *resp)
}
var serializedSCTList []byte
serializedSCTList, err = helpers.SerializeSCTList(sctList)
if err != nil {
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
}
// Serialize again as an octet string before embedding
serializedSCTList, err = asn1.Marshal(serializedSCTList)
if err != nil {
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
}
var SCTListExtension = pkix.Extension{Id: signer.SCTListOID, Critical: false, Value: serializedSCTList}
certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension)
}
var signedCert []byte
signedCert, err = s.sign(&certTBS)
if err != nil {
return nil, err
}
// Get the AKI from signedCert. This is required to support Go 1.9+.
// In prior versions of Go, x509.CreateCertificate updated the
// AuthorityKeyId of certTBS.
parsedCert, _ := helpers.ParseCertificatePEM(signedCert)
if s.dbAccessor != nil {
var certRecord = certdb.CertificateRecord{
Serial: certTBS.SerialNumber.String(),
// this relies on the specific behavior of x509.CreateCertificate
// which sets the AuthorityKeyId from the signer's SubjectKeyId
AKI: hex.EncodeToString(parsedCert.AuthorityKeyId),
CALabel: req.Label,
Status: "good",
Expiry: certTBS.NotAfter,
PEM: string(signedCert),
}
err = s.dbAccessor.InsertCertificate(certRecord)
if err != nil {
return nil, err
}
log.Debug("saved certificate with serial number ", certTBS.SerialNumber)
}
return signedCert, nil
}
// SignFromPrecert creates and signs a certificate from an existing precertificate
// that was previously signed by Signer.ca and inserts the provided SCTs into the
// new certificate. The resulting certificate will be a exact copy of the precert
// except for the removal of the poison extension and the addition of the SCT list
// extension. SignFromPrecert does not verify that the contents of the certificate
// still match the signing profile of the signer, it only requires that the precert
// was previously signed by the Signers CA.
func (s *Signer) SignFromPrecert(precert *x509.Certificate, scts []ct.SignedCertificateTimestamp) ([]byte, error) {
// Verify certificate was signed by s.ca
if err := precert.CheckSignatureFrom(s.ca); err != nil {
return nil, err
}
// Verify certificate is a precert
isPrecert := false
poisonIndex := 0
for i, ext := range precert.Extensions {
if ext.Id.Equal(signer.CTPoisonOID) {
if !ext.Critical {
return nil, cferr.New(cferr.CTError, cferr.PrecertInvalidPoison)
}
// Check extension contains ASN.1 NULL
if bytes.Compare(ext.Value, []byte{0x05, 0x00}) != 0 {
return nil, cferr.New(cferr.CTError, cferr.PrecertInvalidPoison)
}
isPrecert = true
poisonIndex = i
break
}
}
if !isPrecert {
return nil, cferr.New(cferr.CTError, cferr.PrecertMissingPoison)
}
// Serialize SCTs into list format and create extension
serializedList, err := helpers.SerializeSCTList(scts)
if err != nil {
return nil, err
}
// Serialize again as an octet string before embedding
serializedList, err = asn1.Marshal(serializedList)
if err != nil {
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
}
sctExt := pkix.Extension{Id: signer.SCTListOID, Critical: false, Value: serializedList}
// Create the new tbsCert from precert. Do explicit copies of any slices so that we don't
// use memory that may be altered by us or the caller at a later stage.
tbsCert := x509.Certificate{
SignatureAlgorithm: precert.SignatureAlgorithm,
PublicKeyAlgorithm: precert.PublicKeyAlgorithm,
PublicKey: precert.PublicKey,
Version: precert.Version,
SerialNumber: precert.SerialNumber,
Issuer: precert.Issuer,
Subject: precert.Subject,
NotBefore: precert.NotBefore,
NotAfter: precert.NotAfter,
KeyUsage: precert.KeyUsage,
BasicConstraintsValid: precert.BasicConstraintsValid,
IsCA: precert.IsCA,
MaxPathLen: precert.MaxPathLen,
MaxPathLenZero: precert.MaxPathLenZero,
PermittedDNSDomainsCritical: precert.PermittedDNSDomainsCritical,
}
if len(precert.Extensions) > 0 {
tbsCert.ExtraExtensions = make([]pkix.Extension, len(precert.Extensions))
copy(tbsCert.ExtraExtensions, precert.Extensions)
}
// Remove the poison extension from ExtraExtensions
tbsCert.ExtraExtensions = append(tbsCert.ExtraExtensions[:poisonIndex], tbsCert.ExtraExtensions[poisonIndex+1:]...)
// Insert the SCT list extension
tbsCert.ExtraExtensions = append(tbsCert.ExtraExtensions, sctExt)
// Sign the tbsCert
return s.sign(&tbsCert)
}
// Info return a populated info.Resp struct or an error.
func (s *Signer) Info(req info.Req) (resp *info.Resp, err error) {
cert, err := s.Certificate(req.Label, req.Profile)
if err != nil {
return
}
profile, err := signer.Profile(s, req.Profile)
if err != nil {
return
}
resp = new(info.Resp)
if cert.Raw != nil {
resp.Certificate = string(bytes.TrimSpace(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})))
}
resp.Usage = profile.Usage
resp.ExpiryString = profile.ExpiryString
return
}
// SigAlgo returns the RSA signer's signature algorithm.
func (s *Signer) SigAlgo() x509.SignatureAlgorithm {
return s.sigAlgo
}
// Certificate returns the signer's certificate.
func (s *Signer) Certificate(label, profile string) (*x509.Certificate, error) {
cert := *s.ca
return &cert, nil
}
// SetPolicy sets the signer's signature policy.
func (s *Signer) SetPolicy(policy *config.Signing) {
s.policy = policy
}
// SetDBAccessor sets the signers' cert db accessor
func (s *Signer) SetDBAccessor(dba certdb.Accessor) {
s.dbAccessor = dba
}
// GetDBAccessor returns the signers' cert db accessor
func (s *Signer) GetDBAccessor() certdb.Accessor {
return s.dbAccessor
}
// SetReqModifier does nothing for local
func (s *Signer) SetReqModifier(func(*http.Request, []byte)) {
// noop
}
// Policy returns the signer's policy.
func (s *Signer) Policy() *config.Signing {
return s.policy
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
echo '{ "CN": "Pathlen 0 Issuer", "ca": { "pathlen": 0, "pathlenzero": true } }' | cfssl genkey -initca - | cfssljson -bare inter_pathlen_0
echo '{ "CN": "Pathlen 1 Issuer", "ca": { "pathlen": 1 } }' | cfssl genkey -initca - | cfssljson -bare inter_pathlen_1
echo '{ "CN": "Pathlen Unspecified", "ca": {} }' | cfssl genkey -initca - | cfssljson -bare inter_pathlen_unspecified

View File

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEmzCCA4OgAwIBAgIMAMSvNBgypwaaSQ5iMA0GCSqGSIb3DQEBBQUAMIGMMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVT
VCBSb290IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTIx
MjEyMDIxMDMxWhcNMjIxMDIxMDIxMDMxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNV
BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoT
CkNGU1NMIFRFU1QxGzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqG
SIb3DQEJARYPdGVzdEB0ZXN0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAsRp1xSfIDoD/40Bo4Hls3sFn4dav5NgxbZGpVyGF7dJI9u0eEnL4
BUGssPaUFLWC83CZxujUEiEfE0oKX+uOhhGv3+j5xSTNM764m2eSiN53cdZtK05d
hwq9uS8LtjKOQeN1mQ5qmiqxBMdjkKgMsVw5lMCgoYKo57kaKFyXzdpNVDzqw+pt
HWmuNtDQjK3qT5Ma06mYPmIGYhIZYLY7oJGg9ZEaNR0GIw4zIT5JRsNiaSb5wTLw
aa0n/4vLJyVjLJcYmJBvZWj8g+taK+C4INu/jGux+bmsC9hq14tbOaTNAn/NE0qN
8oHwcRBEqfOdEYdZkxI5NWPiKNW/Q+AeXQIDAQABo4H6MIH3MB0GA1UdDgQWBBS3
0veEuqg51fusEM4p/YuWpBPsvTCBxAYDVR0jBIG8MIG5gBS30veEuqg51fusEM4p
/YuWpBPsvaGBkqSBjzCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
aWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkNGU1NMIFRFU1Qx
GzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqGSIb3DQEJARYPdGVz
dEB0ZXN0LmxvY2FsggwAxK80GDKnBppJDmIwDwYDVR0TBAgwBgEB/wIBADANBgkq
hkiG9w0BAQUFAAOCAQEAJ7r1EZYDwed6rS0+YKHdkRGRQ5Rz6A9DIVBPXrSMAGj3
F5EF2m/GJbhpVbnNJTVlgP9DDyabOZNxzdrCr4cHMkYYnocDdgAodnkw6GZ/GJTc
depbVTR4TpihFNzeDEGJePrEwM1DouGswpu97jyuCYZ3z1a60+a+3C1GwWaJ7Aet
Uqm+yLTUrMISsfnDPqJdM1NeqW3jiZ4IgcqJkieCCSpag9Xuzrp9q6rjmePvlQkv
qz020JGg6VijJ+c6Tf5y0XqbAhkBTqYtVamu9gEth9utn12EhdNjTZMPKMjjgFUd
H0N6yOEuQMl4ky7RxZBM0iPyeob6i4z2LEQilgv9MQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGnXFJ8gOgP/j
QGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLzcJnG6NQSIR8T
Sgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B43WZDmqaKrEE
x2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepPkxrTqZg+YgZi
EhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMslxiYkG9laPyD
61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850Rh1mTEjk1Y+Io
1b9D4B5dAgMBAAECggEAKHhjcSomDSptTwDo9mLI/h40HudwSlsc8GzYxZBjinUD
N2n39T9QbeMUE1xFenX/9qFEgq+xxnLLJx1EQacSapCgIAqdCO/f9HMgvGJumdg8
c0cMq1i9Bp7tu+OESZ5D48qWlOM2eQRIb08g8W11eRIaFmPuUPoKnuktkQuXpPJc
YbS/+JuA8SDwe6sV0cMCQuS+iHFfeGwWCKrDUkhLwcL3waW3od2XFyOeFFWFhl0h
HmM/mWKRuRdqR7hrmArTwFZVkB+o/1ywVYXIv+JQm0eNZ5PKLNJGL2f5oxbMR/JI
AoK0bAlJmYaFp96h1KpbPwLEL/0hHSWA7sAyJIgQAQKBgQDaEAZor/w4ZUTekT1+
cbId0yA+ikDXQOfXaNCSh9Pex+Psjd5zVVOqyVFJ29daRju3d7rmpN4Cm5V4h0l1
/2ad207rjCAnpCHtaddJWNyJzF2IL2IaoCZQRp0k7zOjBGQpoWDTwBaEin5CCv3P
kkdQkKz6FDP1xskHSLZr21/QCQKBgQDP6jXutEgGjf3yKpMFk/69EamJdon8clbt
hl7cOyWtobnZhdOWVZPe00Oo3Jag2aWgFFsm3EtwnUCnR4d4+fXRKS2LkhfIUZcz
cKy17Ileggdd8UGhL4RDrF/En9tJL86WcVkcoOrqLcGB2FLWrVhVpHFK74eLMCH/
uc/+ioPItQKBgHYoDsD08s7AGMQcoNx90MyWVLduhFnegoFW+wUa8jOZzieka6/E
wVQeR5yksZjpy3vLNYu6M83n7eLkM2rrm/fXGHlLcTTpm7SgEBZfPwivotKjEh5p
PrlqucWEk082lutz1RqHz+u7e1Rfzk2F7nx6GDBdeBYpw03eGXJx6QW5AoGBAIJq
4puyAEAET1fZNtHX7IGCk7sDXTi6LCbgE57HhzHr8V0t4fQ6CABMuvMwM1gATjEk
s6yjoLqqGUUUzDipanViBAy5fiuManC868lN7zkWDTLzQ3ytBqVAee4na/DziP27
ae9YTSLJwskE/alloLRP6zTbHUXE0n7LelmrX1DFAoGBAMFLl+Lu+WFgCHxBjn43
rHpJbQZQmsFhAMhkN4hsj6dJfAGn2gRLRiVRAika+8QF65xMZiVQWUVSUZADWERi
0SXGjzN1wYxO3Qzy3LYwws6fxFAq5lo79eb38yFT2lHdqK3x/QgiDSRVl+R6cExV
xQB518/lp2eIeMpglWByDwJX
-----END PRIVATE KEY-----

View File

@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBezCCASECAQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJl
LWludGVyLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgOKlWwIAIeURde
yvDMhgfn6xPp1gn8oUeLmsniBm7I+j84IsVzUso8/MpjMZ9nB8lQUanhv3Kmqcyj
HNj+iFegMjAwBgkqhkiG9w0BCQ4xIzAhMB8GA1UdEQQYMBaCFGNsb3VkZmxhcmUt
aW50ZXIuY29tMAoGCCqGSM49BAMCA0gAMEUCIEJcy2mn2YyK8lVE+HHmr2OsmdbH
4CLDVXFBwxke8ObqAiEAx/il1cDKvQ/I36b4XjBnOX2jcQ5oaCNPFFBE74WQ/ps=
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEILbwI4u4bw+HtafMqFnrL7LOrqNEZH5rW5ygSrigfrVLoAoGCCqGSM49
AwEHoUQDQgAEuA4qVbAgAh5RF17K8MyGB+frE+nWCfyhR4uayeIGbsj6PzgixXNS
yjz8ymMxn2cHyVBRqeG/cqapzKMc2P6IVw==
-----END EC PRIVATE KEY-----

Some files were not shown because too many files have changed in this diff Show More