// jwsEncodeJSON signs claimset using provided key and a nonce. // The result is serialized in JSON format. // See https://tools.ietf.org/html/rfc7515#section-7. func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) { jwk, err := jwkEncode(key.Public()) if err != nil { return nil, err } phead := fmt.Sprintf(`{"alg":"RS256","jwk":%s,"nonce":%q}`, jwk, nonce) phead = base64.RawURLEncoding.EncodeToString([]byte(phead)) cs, err := json.Marshal(claimset) if err != nil { return nil, err } payload := base64.RawURLEncoding.EncodeToString(cs) h := sha256.New() h.Write([]byte(phead + "." + payload)) sig, err := key.Sign(rand.Reader, h.Sum(nil), crypto.SHA256) if err != nil { return nil, err } enc := struct { Protected string `json:"protected"` Payload string `json:"payload"` Sig string `json:"signature"` }{ Protected: phead, Payload: payload, Sig: base64.RawURLEncoding.EncodeToString(sig), } return json.Marshal(&enc) }
// jwsEncodeJSON signs claimset using provided key and a nonce. // The result is serialized in JSON format. // See https://tools.ietf.org/html/rfc7515#section-7. func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) { jwk, err := jwkEncode(key.Public()) if err != nil { return nil, err } alg, sha := jwsHasher(key) if alg == "" || !sha.Available() { return nil, ErrUnsupportedKey } phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce) phead = base64.RawURLEncoding.EncodeToString([]byte(phead)) cs, err := json.Marshal(claimset) if err != nil { return nil, err } payload := base64.RawURLEncoding.EncodeToString(cs) hash := sha.New() hash.Write([]byte(phead + "." + payload)) sig, err := jwsSign(key, sha, hash.Sum(nil)) if err != nil { return nil, err } enc := struct { Protected string `json:"protected"` Payload string `json:"payload"` Sig string `json:"signature"` }{ Protected: phead, Payload: payload, Sig: base64.RawURLEncoding.EncodeToString(sig), } return json.Marshal(&enc) }
// Add adds a new key to the server's internal repertoire. // Stores in maps by SKI and (if possible) Digest, SNI, Server IP, and Client IP. func (keys *defaultKeystore) Add(op *gokeyless.Operation, priv crypto.Signer) error { ski, err := gokeyless.GetSKI(priv.Public()) if err != nil { return err } keys.Lock() defer keys.Unlock() if digest, err := gokeyless.GetDigest(priv.Public()); err == nil { keys.digests[digest] = ski } if op != nil { if op.SNI != "" { keys.snis[op.SNI] = ski } if op.ServerIP != nil { keys.serverIPs[op.ServerIP.String()] = ski } if op.ClientIP != nil { keys.clientIPs[op.ClientIP.String()] = ski } keys.validAKIs[ski] = keys.validAKIs[ski].Add(op.AKI) } keys.skis[ski] = priv log.Debugf("Adding key with SKI: %02x", ski) return nil }
// DefaultSigAlgo returns an appropriate X.509 signature algorithm given // the CA's private key. func DefaultSigAlgo(priv crypto.Signer) x509.SignatureAlgorithm { pub := priv.Public() switch pub := pub.(type) { case *rsa.PublicKey: keySize := pub.N.BitLen() switch { case keySize >= 4096: return x509.SHA512WithRSA case keySize >= 3072: return x509.SHA384WithRSA case keySize >= 2048: return x509.SHA256WithRSA default: return x509.SHA1WithRSA } case *ecdsa.PublicKey: switch pub.Curve { case elliptic.P256(): return x509.ECDSAWithSHA256 case elliptic.P384(): return x509.ECDSAWithSHA384 case elliptic.P521(): return x509.ECDSAWithSHA512 default: return x509.ECDSAWithSHA1 } default: return x509.UnknownSignatureAlgorithm } }
// NewSignerFromSigner takes any crypto.Signer implementation and // returns a corresponding Signer interface. This can be used, for // example, with keys kept in hardware modules. func NewSignerFromSigner(signer crypto.Signer) (Signer, error) { pubKey, err := NewPublicKey(signer.Public()) if err != nil { return nil, err } return &wrappedSigner{signer, pubKey}, nil }
func generateCertificate(t *testing.T, signer crypto.Signer, out io.Writer) { derBytes, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, signer.Public(), signer) if err != nil { t.Fatal("Unable to generate a certificate", err.Error()) } if err = pem.Encode(out, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { t.Fatal("Unable to write cert to file", err.Error()) } }
// GetSubjKeyID returns the subject key ID, e.g. the SHA1 sum // of the marshaled public key func GetSubjKeyID(privateKey crypto.Signer) ([]byte, error) { if privateKey == nil { return nil, InternalError{"passed-in private key is nil"} } marshaledKey, err := x509.MarshalPKIXPublicKey(privateKey.Public()) if err != nil { return nil, InternalError{fmt.Sprintf("error marshalling public key: %s", err)} } subjKeyID := sha1.Sum(marshaledKey) return subjKeyID[:], nil }
// jwsHasher indicates suitable JWS algorithm name and a hash function // to use for signing a digest with the provided key. // It returns ("", 0) if the key is not supported. func jwsHasher(key crypto.Signer) (string, crypto.Hash) { switch key := key.(type) { case *rsa.PrivateKey: return "RS256", crypto.SHA256 case *ecdsa.PrivateKey: switch key.Params().Name { case "P-256": return "ES256", crypto.SHA256 case "P-384": return "ES384", crypto.SHA384 case "P-512": return "ES512", crypto.SHA512 } } return "", 0 }
// SignerAlgo returns an X.509 signature algorithm corresponding to // the crypto.Hash provided from a crypto.Signer. func SignerAlgo(priv crypto.Signer, h crypto.Hash) x509.SignatureAlgorithm { switch priv.Public().(type) { case *rsa.PublicKey: switch h { case crypto.SHA512: return x509.SHA512WithRSA case crypto.SHA384: return x509.SHA384WithRSA case crypto.SHA256: return x509.SHA256WithRSA default: return x509.SHA1WithRSA } case *ecdsa.PublicKey: switch h { case crypto.SHA512: return x509.ECDSAWithSHA512 case crypto.SHA384: return x509.ECDSAWithSHA384 case crypto.SHA256: return x509.ECDSAWithSHA256 default: return x509.ECDSAWithSHA1 } default: return x509.UnknownSignatureAlgorithm } }
// NewSignTests generates a map of test name to TestFunc that performs an opaque sign and verify. func NewSignTests(priv crypto.Signer) map[string]testapi.TestFunc { tests := make(map[string]testapi.TestFunc) ptxt := []byte("Test Plaintext") r := rand.Reader hashes := map[string]crypto.Hash{ "sign.md5sha1": crypto.MD5SHA1, "sign.sha1": crypto.SHA1, "sign.sha224": crypto.SHA224, "sign.sha256": crypto.SHA256, "sign.sha384": crypto.SHA384, "sign.sha512": crypto.SHA512, } for hashName, h := range hashes { var msg []byte if h == crypto.MD5SHA1 { msg = append(hashPtxt(crypto.MD5, ptxt), hashPtxt(crypto.SHA1, ptxt)...) } else { msg = hashPtxt(h, ptxt) } tests[hashName] = func(h crypto.Hash) testapi.TestFunc { return func() error { sig, err := priv.Sign(r, msg, h) if err != nil { return err } switch pub := priv.Public().(type) { case *rsa.PublicKey: return rsa.VerifyPKCS1v15(pub, h, msg, sig) case *ecdsa.PublicKey: ecdsaSig := new(struct{ R, S *big.Int }) asn1.Unmarshal(sig, ecdsaSig) if !ecdsa.Verify(pub, msg, ecdsaSig.R, ecdsaSig.S) { return errors.New("ecdsa verify failed") } default: return errors.New("unknown public key type") } return nil } }(h) } return tests }
// NewFromSigner creates a new root certificate from a crypto.Signer. func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) { if req.CA != nil { if req.CA.Expiry != "" { CAPolicy.Default.ExpiryString = req.CA.Expiry CAPolicy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry) if err != nil { return nil, nil, err } } if req.CA.PathLength != 0 { signer.MaxPathLen = req.CA.PathLength } } var sigAlgo x509.SignatureAlgorithm switch pub := priv.Public().(type) { case *rsa.PublicKey: bitLength := pub.N.BitLen() switch { case bitLength >= 4096: sigAlgo = x509.SHA512WithRSA case bitLength >= 3072: sigAlgo = x509.SHA384WithRSA case bitLength >= 2048: sigAlgo = x509.SHA256WithRSA default: sigAlgo = x509.SHA1WithRSA } case *ecdsa.PublicKey: switch pub.Curve { case elliptic.P521(): sigAlgo = x509.ECDSAWithSHA512 case elliptic.P384(): sigAlgo = x509.ECDSAWithSHA384 case elliptic.P256(): sigAlgo = x509.ECDSAWithSHA256 default: sigAlgo = x509.ECDSAWithSHA1 } default: sigAlgo = x509.UnknownSignatureAlgorithm } 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 { tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i]) } } return signWithCSR(&tpl, priv) }
// tlsChallengeCert creates a temporary certificate for TLS-SNI challenges // with the given SANs and auto-generated public/private key pair. // To create a cert with a custom key pair, specify WithKey option. func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) { var ( key crypto.Signer tmpl *x509.Certificate ) for _, o := range opt { switch o := o.(type) { case *certOptKey: if key != nil { return tls.Certificate{}, errors.New("acme: duplicate key option") } key = o.key case *certOptTemplate: var t = *(*x509.Certificate)(o) // shallow copy is ok tmpl = &t default: // package's fault, if we let this happen: panic(fmt.Sprintf("unsupported option type %T", o)) } } if key == nil { var err error if key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader); err != nil { return tls.Certificate{}, err } } if tmpl == nil { tmpl = &x509.Certificate{ SerialNumber: big.NewInt(1), NotBefore: time.Now(), NotAfter: time.Now().Add(24 * time.Hour), BasicConstraintsValid: true, KeyUsage: x509.KeyUsageKeyEncipherment, } } tmpl.DNSNames = san der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key) if err != nil { return tls.Certificate{}, err } return tls.Certificate{ Certificate: [][]byte{der}, PrivateKey: key, }, nil }
// RegisterKey adds a new key to the server's internal repertoire. func (s *Server) RegisterKey(key crypto.Signer) error { ski, err := gokeyless.GetSKI(key.Public()) if err != nil { return err } s.Lock() defer s.Unlock() if digest, ok := gokeyless.GetDigest(key.Public()); ok { s.digests[digest] = ski } s.keys[ski] = key s.Log.Printf("Registering key with SKI: %X", ski) return nil }
func generateCertificate(signer crypto.Signer, gun string, startTime, endTime time.Time) (*x509.Certificate, error) { template, err := trustmanager.NewCertificate(gun, startTime, endTime) if err != nil { return nil, fmt.Errorf("failed to create the certificate template for: %s (%v)", gun, err) } derBytes, err := x509.CreateCertificate(rand.Reader, template, template, signer.Public(), signer) if err != nil { return nil, fmt.Errorf("failed to create the certificate for: %s (%v)", gun, err) } cert, err := x509.ParseCertificate(derBytes) if err != nil { return nil, fmt.Errorf("failed to parse the certificate for key: %s (%v)", gun, err) } return cert, nil }
func NewBlock(old *Block, prf PoS, ts []Transaction, signer crypto.Signer) *Block { oldH, err := old.Hash.MarshalBinary() if err != nil { panic(err) } prevHash := sha3.Sum256(oldH) h := Hash{ Hash: prevHash[:], Proof: prf, } var tsBytes []byte for i := range ts { b, err := ts[i].MarshalBinary() if err != nil { panic(err) } tsBytes = append(tsBytes, b...) } sigBytes := util.Concat([][]byte{old.Sig.Tsig, old.Sig.Ssig}) tsig, err := signer.Sign(rand.Reader, tsBytes, crypto.SHA3_256) if err != nil { panic(err) } ssig, err := signer.Sign(rand.Reader, sigBytes, crypto.SHA3_256) if err != nil { panic(err) } sig := Signature{ Tsig: tsig, Ssig: ssig, } b := Block{ Id: old.Id + 1, Hash: h, Trans: ts, Sig: sig, } return &b }
func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) { signature, err := k.Sign(rand.Reader, hashed, hash) if err != nil { return nil, err } switch alg { case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512: return signature, nil case ECDSAP256SHA256, ECDSAP384SHA384: ecdsaSignature := &struct { R, S *big.Int }{} if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil { return nil, err } var intlen int switch alg { case ECDSAP256SHA256: intlen = 32 case ECDSAP384SHA384: intlen = 48 } signature := intToBytes(ecdsaSignature.R, intlen) signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...) return signature, nil // There is no defined interface for what a DSA backed crypto.Signer returns case DSA, DSANSEC3SHA1: // t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8) // signature := []byte{byte(t)} // signature = append(signature, intToBytes(r1, 20)...) // signature = append(signature, intToBytes(s1, 20)...) // rr.Signature = signature } return nil, ErrAlg }
// jwsSign signs the digest using the given key. // It returns ErrUnsupportedKey if the key type is unknown. // The hash is used only for RSA keys. func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) { switch key := key.(type) { case *rsa.PrivateKey: return key.Sign(rand.Reader, digest, hash) case *ecdsa.PrivateKey: r, s, err := ecdsa.Sign(rand.Reader, key, digest) if err != nil { return nil, err } rb, sb := r.Bytes(), s.Bytes() size := key.Params().BitSize / 8 if size%8 > 0 { size++ } sig := make([]byte, size*2) copy(sig[size-len(rb):], rb) copy(sig[size*2-len(sb):], sb) return sig, nil } return nil, ErrUnsupportedKey }
// NewSignerPrivateKey creates a sign-only PrivateKey from a crypto.Signer that // implements RSA or ECDSA. func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *PrivateKey { pk := new(PrivateKey) switch pubkey := signer.Public().(type) { case rsa.PublicKey: pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) pk.PubKeyAlgo = PubKeyAlgoRSASignOnly case ecdsa.PublicKey: pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) default: panic("openpgp: unknown crypto.Signer type in NewSignerPrivateKey") } pk.PrivateKey = signer return pk }
// 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 exsiting 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 }
// CreateResponse returns a DER-encoded OCSP response with the specified contents. // The fields in the response are populated as follows: // // The responder cert is used to populate the ResponderName field, and the certificate // itself is provided alongside the OCSP response signature. // // The issuer cert is used to puplate the IssuerNameHash and IssuerKeyHash fields. // (SHA-1 is used for the hash function; this is not configurable.) // // The template is used to populate the SerialNumber, RevocationStatus, RevokedAt, // RevocationReason, ThisUpdate, and NextUpdate fields. // // The ProducedAt date is automatically set to the current date, to the nearest minute. func CreateResponse(issuer, responderCert *x509.Certificate, template Response, priv crypto.Signer) ([]byte, error) { var publicKeyInfo struct { Algorithm pkix.AlgorithmIdentifier PublicKey asn1.BitString } if _, err := asn1.Unmarshal(issuer.RawSubjectPublicKeyInfo, &publicKeyInfo); err != nil { return nil, err } h := sha1.New() h.Write(publicKeyInfo.PublicKey.RightAlign()) issuerKeyHash := h.Sum(nil) h.Reset() h.Write(issuer.RawSubject) issuerNameHash := h.Sum(nil) innerResponse := singleResponse{ CertID: certID{ HashAlgorithm: pkix.AlgorithmIdentifier{ Algorithm: hashOIDs[crypto.SHA1], Parameters: asn1.RawValue{Tag: 5 /* ASN.1 NULL */}, }, NameHash: issuerNameHash, IssuerKeyHash: issuerKeyHash, SerialNumber: template.SerialNumber, }, ThisUpdate: template.ThisUpdate.UTC(), NextUpdate: template.NextUpdate.UTC(), SingleExtensions: template.ExtraExtensions, } switch template.Status { case Good: innerResponse.Good = true case Unknown: innerResponse.Unknown = true case Revoked: innerResponse.Revoked = revokedInfo{ RevocationTime: template.RevokedAt.UTC(), Reason: asn1.Enumerated(template.RevocationReason), } } responderName := asn1.RawValue{ Class: 2, // context-specific Tag: 1, // explicit tag IsCompound: true, Bytes: responderCert.RawSubject, } tbsResponseData := responseData{ Version: 0, RawResponderName: responderName, ProducedAt: time.Now().Truncate(time.Minute).UTC(), Responses: []singleResponse{innerResponse}, } tbsResponseDataDER, err := asn1.Marshal(tbsResponseData) if err != nil { return nil, err } hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm) if err != nil { return nil, err } responseHash := hashFunc.New() responseHash.Write(tbsResponseDataDER) signature, err := priv.Sign(rand.Reader, responseHash.Sum(nil), hashFunc) if err != nil { return nil, err } response := basicResponse{ TBSResponseData: tbsResponseData, SignatureAlgorithm: signatureAlgorithm, Signature: asn1.BitString{ Bytes: signature, BitLength: 8 * len(signature), }, } if template.Certificate != nil { response.Certificates = []asn1.RawValue{ asn1.RawValue{FullBytes: template.Certificate.Raw}, } } responseDER, err := asn1.Marshal(response) if err != nil { return nil, err } return asn1.Marshal(responseASN1{ Status: asn1.Enumerated(Success), Response: responseBytes{ ResponseType: idPKIXOCSPBasic, Response: responseDER, }, }) }
// Bundle takes an X509 certificate (already in the // Certificate structure), a private key as crypto.Signer in one of the appropriate // formats (i.e. *rsa.PrivateKey or *ecdsa.PrivateKey, or even a opaque key), using them to // build a certificate bundle. func (b *Bundler) Bundle(certs []*x509.Certificate, key crypto.Signer, flavor BundleFlavor) (*Bundle, error) { log.Infof("bundling certificate for %+v", certs[0].Subject) if len(certs) == 0 { return nil, nil } // Detect reverse ordering of the cert chain. if len(certs) > 1 && !partialVerify(certs) { rcerts := reverse(certs) if partialVerify(rcerts) { certs = rcerts } } var ok bool cert := certs[0] if key != nil { switch { case cert.PublicKeyAlgorithm == x509.RSA: var rsaPublicKey *rsa.PublicKey if rsaPublicKey, ok = key.Public().(*rsa.PublicKey); !ok { return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch) } if cert.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 { return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch) } case cert.PublicKeyAlgorithm == x509.ECDSA: var ecdsaPublicKey *ecdsa.PublicKey if ecdsaPublicKey, ok = key.Public().(*ecdsa.PublicKey); !ok { return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch) } if cert.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 { return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch) } default: return nil, errors.New(errors.PrivateKeyError, errors.NotRSAOrECC) } } else { switch { case cert.PublicKeyAlgorithm == x509.RSA: case cert.PublicKeyAlgorithm == x509.ECDSA: default: return nil, errors.New(errors.PrivateKeyError, errors.NotRSAOrECC) } } if cert.CheckSignatureFrom(cert) == nil { return nil, errors.New(errors.CertificateError, errors.SelfSigned) } bundle := new(Bundle) bundle.Cert = cert bundle.Key = key bundle.Issuer = &cert.Issuer bundle.Subject = &cert.Subject bundle.buildHostnames() // verify and store input intermediates to the intermediate pool. // Ignore the returned error here, will treat it in the second call. b.fetchIntermediates(certs) chains, err := cert.Verify(b.VerifyOptions()) if err != nil { log.Debugf("verification failed: %v", err) // If the error was an unknown authority, try to fetch // the intermediate specified in the AIA and add it to // the intermediates bundle. switch err := err.(type) { case x509.UnknownAuthorityError: // Do nothing -- have the default case return out. default: return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } log.Debugf("searching for intermediates via AIA issuer") err = b.fetchIntermediates(certs) if err != nil { log.Debugf("search failed: %v", err) return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } log.Debugf("verifying new chain") chains, err = cert.Verify(b.VerifyOptions()) if err != nil { log.Debugf("failed to verify chain: %v", err) return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } log.Debugf("verify ok") } var matchingChains [][]*x509.Certificate switch flavor { case Optimal: matchingChains = optimalChains(chains) case Ubiquitous: if len(ubiquity.Platforms) == 0 { log.Warning("No metadata, Ubiquitous falls back to Optimal.") } matchingChains = ubiquitousChains(chains) case Force: matchingChains = forceChains(certs, chains) default: matchingChains = ubiquitousChains(chains) } bundle.Chain = matchingChains[0] // Include at least one intermediate if the leaf has enabled OCSP and is not CA. if bundle.Cert.OCSPServer != nil && !bundle.Cert.IsCA && len(bundle.Chain) <= 2 { // No op. Return one intermediate if there is one. } else { // do not include the root. bundle.Chain = bundle.Chain[:len(bundle.Chain)-1] } statusCode := int(errors.Success) var messages []string // Check if bundle is expiring. expiringCerts := checkExpiringCerts(bundle.Chain) bundle.Expires = helpers.ExpiryTime(bundle.Chain) if len(expiringCerts) > 0 { statusCode |= errors.BundleExpiringBit messages = append(messages, expirationWarning(expiringCerts)) } // Check if bundle contains SHA2 certs. if ubiquity.ChainHashUbiquity(matchingChains[0]) <= ubiquity.SHA2Ubiquity { statusCode |= errors.BundleNotUbiquitousBit messages = append(messages, sha2Warning) } // Check if bundle contains ECDSA signatures. if ubiquity.ChainKeyAlgoUbiquity(matchingChains[0]) <= ubiquity.ECDSA256Ubiquity { statusCode |= errors.BundleNotUbiquitousBit messages = append(messages, ecdsaWarning) } // Add root store presence info root := matchingChains[0][len(matchingChains[0])-1] bundle.Root = root log.Infof("the anchoring root is %v", root.Subject) // Check if there is any platform that doesn't trust the chain. // Also, an warning will be generated if ubiquity.Platforms is nil, untrusted := ubiquity.UntrustedPlatforms(root) untrustedMsg := untrustedPlatformsWarning(untrusted) if len(untrustedMsg) > 0 { log.Debug("Populate untrusted platform warning.") statusCode |= errors.BundleNotUbiquitousBit messages = append(messages, untrustedMsg) } // Check if there is any platform that rejects the chain because of SHA1 deprecation. deprecated := ubiquity.DeprecatedSHA1Platforms(matchingChains[0]) if len(deprecated) > 0 { log.Debug("Populate SHA1 deprecation warning.") statusCode |= errors.BundleNotUbiquitousBit messages = append(messages, deprecateSHA1Warning(deprecated)) } bundle.Status = &BundleStatus{ExpiringSKIs: getSKIs(bundle.Chain, expiringCerts), Code: statusCode, Messages: messages, Untrusted: untrusted} bundle.Status.IsRebundled = diff(bundle.Chain, certs) log.Debugf("bundle complete") return bundle, nil }
// NewFromSigner creates a new root certificate from a crypto.Signer. func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) { var sigAlgo x509.SignatureAlgorithm switch pub := priv.Public().(type) { case *rsa.PublicKey: bitLength := pub.N.BitLen() switch { case bitLength >= 4096: sigAlgo = x509.SHA512WithRSA case bitLength >= 3072: sigAlgo = x509.SHA384WithRSA case bitLength >= 2048: sigAlgo = x509.SHA256WithRSA default: sigAlgo = x509.SHA1WithRSA } case *ecdsa.PublicKey: switch pub.Curve { case elliptic.P521(): sigAlgo = x509.ECDSAWithSHA512 case elliptic.P384(): sigAlgo = x509.ECDSAWithSHA384 case elliptic.P256(): sigAlgo = x509.ECDSAWithSHA256 default: sigAlgo = x509.ECDSAWithSHA1 } default: sigAlgo = x509.UnknownSignatureAlgorithm } var tpl = x509.CertificateRequest{ Subject: req.Name(), SignatureAlgorithm: sigAlgo, DNSNames: req.Hosts, } csrPEM, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv) if err != nil { log.Errorf("failed to generate a CSR: %v", err) // The use of CertificateError was a matter of some // debate; it is the one edge case in which a new // error category specifically for CSRs might be // useful, but it was deemed that one edge case did // not a new category justify. err = cferr.Wrap(cferr.CertificateError, cferr.BadRequest, err) return } p := &pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: csrPEM, } csrPEM = pem.EncodeToMemory(p) s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), nil) if err != nil { log.Errorf("failed to create signer: %v", err) return } s.SetPolicy(CAPolicy) signReq := signer.SignRequest{Request: string(csrPEM)} cert, err = s.Sign(signReq) return }
func (s *Server) handle(conn *gokeyless.Conn) { defer conn.Close() s.Log.Println("Handling new connection...") // Continuosly read request Headers from conn and respond // until a connection error (Read/Write failure) is encountered. var connError error for connError == nil { conn.SetDeadline(time.Now().Add(time.Hour)) var h *gokeyless.Header if h, connError = conn.ReadHeader(); connError != nil { continue } s.Log.Printf("version:%d.%d id:%d body:%s", h.MajorVers, h.MinorVers, h.ID, h.Body) var opts crypto.SignerOpts var isRSA bool var key crypto.Signer var ok bool switch h.Body.Opcode { case gokeyless.OpPing: connError = conn.RespondPong(h.ID, h.Body.Payload) continue case gokeyless.OpRSADecrypt: if key, ok = s.getKey(h.Body.SKI, h.Body.Digest); !ok { s.Log.Println(gokeyless.ErrKeyNotFound) connError = conn.RespondError(h.ID, gokeyless.ErrKeyNotFound) continue } if _, ok = key.Public().(*rsa.PublicKey); !ok { s.Log.Printf("%s: Key is not RSA\n", gokeyless.ErrCrypto) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) continue } rsaKey, ok := key.(crypto.Decrypter) if !ok { s.Log.Printf("%s: Key is not Decrypter\n", gokeyless.ErrCrypto) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) continue } ptxt, err := rsaKey.Decrypt(nil, h.Body.Payload, nil) if err != nil { s.Log.Printf("%s: Decryption error: %v", gokeyless.ErrCrypto, err) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) continue } connError = conn.Respond(h.ID, ptxt) continue case gokeyless.OpRSASignMD5SHA1: isRSA = true fallthrough case gokeyless.OpECDSASignMD5SHA1: opts = crypto.MD5SHA1 case gokeyless.OpRSASignSHA1: isRSA = true fallthrough case gokeyless.OpECDSASignSHA1: opts = crypto.SHA1 case gokeyless.OpRSASignSHA224: case gokeyless.OpECDSASignSHA224: opts = crypto.SHA224 case gokeyless.OpRSASignSHA256: isRSA = true fallthrough case gokeyless.OpECDSASignSHA256: opts = crypto.SHA256 case gokeyless.OpRSASignSHA384: isRSA = true fallthrough case gokeyless.OpECDSASignSHA384: opts = crypto.SHA384 case gokeyless.OpRSASignSHA512: isRSA = true fallthrough case gokeyless.OpECDSASignSHA512: opts = crypto.SHA512 case gokeyless.OpPong: fallthrough case gokeyless.OpResponse: fallthrough case gokeyless.OpError: s.Log.Printf("%s: %s is not a valid request Opcode\n", gokeyless.ErrUnexpectedOpcode, h.Body.Opcode) connError = conn.RespondError(h.ID, gokeyless.ErrUnexpectedOpcode) continue default: connError = conn.RespondError(h.ID, gokeyless.ErrBadOpcode) continue } if key, ok = s.getKey(h.Body.SKI, h.Body.Digest); !ok { s.Log.Println(gokeyless.ErrKeyNotFound) connError = conn.RespondError(h.ID, gokeyless.ErrKeyNotFound) continue } // Ensure we don't perform an ECDSA sign for an RSA request. if _, ok := key.Public().(*rsa.PublicKey); isRSA && !ok { s.Log.Printf("%s: request is RSA, but key is ECDSA\n", gokeyless.ErrCrypto) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) continue } sig, err := key.Sign(rand.Reader, h.Body.Payload, opts) if err != nil { s.Log.Printf("%s: Signing error: %v\n", gokeyless.ErrCrypto, err) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) continue } connError = conn.Respond(h.ID, sig) } s.Log.Printf("Connection error: %v\n", connError) return }
// Performs the heavy lifting of creating a certificate. Returns // a fully-filled-in ParsedCertBundle. func createCertificate(creationInfo *certCreationBundle) (*certutil.ParsedCertBundle, error) { var clientPrivKey crypto.Signer var err error result := &certutil.ParsedCertBundle{} var serialNumber *big.Int serialNumber, err = rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil)) if err != nil { return nil, certutil.InternalError{Err: fmt.Sprintf("Error getting random serial number")} } switch creationInfo.KeyType { case "rsa": result.PrivateKeyType = certutil.RSAPrivateKey clientPrivKey, err = rsa.GenerateKey(rand.Reader, creationInfo.KeyBits) if err != nil { return nil, certutil.InternalError{Err: fmt.Sprintf("Error generating RSA private key")} } result.PrivateKey = clientPrivKey result.PrivateKeyBytes = x509.MarshalPKCS1PrivateKey(clientPrivKey.(*rsa.PrivateKey)) case "ec": result.PrivateKeyType = certutil.ECPrivateKey var curve elliptic.Curve switch creationInfo.KeyBits { case 224: curve = elliptic.P224() case 256: curve = elliptic.P256() case 384: curve = elliptic.P384() case 521: curve = elliptic.P521() default: return nil, certutil.UserError{Err: fmt.Sprintf("Unsupported bit length for EC key: %d", creationInfo.KeyBits)} } clientPrivKey, err = ecdsa.GenerateKey(curve, rand.Reader) if err != nil { return nil, certutil.InternalError{Err: fmt.Sprintf("Error generating EC private key")} } result.PrivateKey = clientPrivKey result.PrivateKeyBytes, err = x509.MarshalECPrivateKey(clientPrivKey.(*ecdsa.PrivateKey)) if err != nil { return nil, certutil.InternalError{Err: fmt.Sprintf("Error marshalling EC private key")} } default: return nil, certutil.UserError{Err: fmt.Sprintf("Unknown key type: %s", creationInfo.KeyType)} } subjKeyID, err := certutil.GetSubjKeyID(result.PrivateKey) if err != nil { return nil, certutil.InternalError{Err: fmt.Sprintf("Error getting subject key ID: %s", err)} } subject := pkix.Name{ Country: creationInfo.CACert.Subject.Country, Organization: creationInfo.CACert.Subject.Organization, OrganizationalUnit: creationInfo.CACert.Subject.OrganizationalUnit, Locality: creationInfo.CACert.Subject.Locality, Province: creationInfo.CACert.Subject.Province, StreetAddress: creationInfo.CACert.Subject.StreetAddress, PostalCode: creationInfo.CACert.Subject.PostalCode, SerialNumber: serialNumber.String(), CommonName: creationInfo.CommonNames[0], } certTemplate := &x509.Certificate{ SignatureAlgorithm: x509.SHA256WithRSA, SerialNumber: serialNumber, Subject: subject, NotBefore: time.Now(), NotAfter: time.Now().Add(creationInfo.Lease), KeyUsage: x509.KeyUsage(x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement), BasicConstraintsValid: true, IsCA: false, SubjectKeyId: subjKeyID, DNSNames: creationInfo.CommonNames, IPAddresses: creationInfo.IPSANs, PermittedDNSDomainsCritical: false, PermittedDNSDomains: nil, CRLDistributionPoints: creationInfo.CACert.CRLDistributionPoints, } if creationInfo.Usage&serverUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageServerAuth) } if creationInfo.Usage&clientUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageClientAuth) } if creationInfo.Usage&codeSigningUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageCodeSigning) } cert, err := x509.CreateCertificate(rand.Reader, certTemplate, creationInfo.CACert, clientPrivKey.Public(), creationInfo.SigningBundle.PrivateKey) if err != nil { return nil, certutil.InternalError{Err: fmt.Sprintf("Unable to create certificate: %s", err)} } result.CertificateBytes = cert result.Certificate, err = x509.ParseCertificate(cert) if err != nil { return nil, certutil.InternalError{Err: fmt.Sprintf("Unable to parse created certificate: %s", err)} } result.IssuingCABytes = creationInfo.SigningBundle.CertificateBytes result.IssuingCA = creationInfo.SigningBundle.Certificate return result, nil }
func (s *Server) handle(conn *gokeyless.Conn) { defer conn.Close() log.Debug("Handling new connection...") // Continuosly read request Headers from conn and respond // until a connection error (Read/Write failure) is encountered. var connError error for connError == nil { conn.SetDeadline(time.Now().Add(time.Hour)) var h *gokeyless.Header if h, connError = conn.ReadHeader(); connError != nil { continue } requestBegin := time.Now() log.Debugf("version:%d.%d id:%d body:%s", h.MajorVers, h.MinorVers, h.ID, h.Body) var opts crypto.SignerOpts var key crypto.Signer var ok bool switch h.Body.Opcode { case gokeyless.OpPing: connError = conn.RespondPong(h.ID, h.Body.Payload) s.stats.logRequest(requestBegin) continue case gokeyless.OpRSADecrypt: if key, ok = s.Keys.Get(h.Body); !ok { log.Error(gokeyless.ErrKeyNotFound) connError = conn.RespondError(h.ID, gokeyless.ErrKeyNotFound) s.stats.logInvalid(requestBegin) continue } if _, ok = key.Public().(*rsa.PublicKey); !ok { log.Errorf("%s: Key is not RSA\n", gokeyless.ErrCrypto) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) s.stats.logInvalid(requestBegin) continue } rsaKey, ok := key.(crypto.Decrypter) if !ok { log.Errorf("%s: Key is not Decrypter\n", gokeyless.ErrCrypto) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) s.stats.logInvalid(requestBegin) continue } ptxt, err := rsaKey.Decrypt(nil, h.Body.Payload, nil) if err != nil { log.Errorf("%s: Decryption error: %v", gokeyless.ErrCrypto, err) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) s.stats.logInvalid(requestBegin) continue } connError = conn.Respond(h.ID, ptxt) s.stats.logRequest(requestBegin) continue case gokeyless.OpRSASignMD5SHA1, gokeyless.OpECDSASignMD5SHA1: opts = crypto.MD5SHA1 case gokeyless.OpRSASignSHA1, gokeyless.OpECDSASignSHA1: opts = crypto.SHA1 case gokeyless.OpRSASignSHA224, gokeyless.OpECDSASignSHA224: opts = crypto.SHA224 case gokeyless.OpRSASignSHA256, gokeyless.OpECDSASignSHA256: opts = crypto.SHA256 case gokeyless.OpRSASignSHA384, gokeyless.OpECDSASignSHA384: opts = crypto.SHA384 case gokeyless.OpRSASignSHA512, gokeyless.OpECDSASignSHA512: opts = crypto.SHA512 case gokeyless.OpActivate: if len(s.ActivationToken) > 0 { hashedToken := sha256.Sum256(s.ActivationToken) connError = conn.Respond(h.ID, hashedToken[:]) s.stats.logRequest(requestBegin) } else { connError = conn.RespondError(h.ID, gokeyless.ErrBadOpcode) s.stats.logInvalid(requestBegin) } continue case gokeyless.OpPong, gokeyless.OpResponse, gokeyless.OpError: log.Errorf("%s: %s is not a valid request Opcode\n", gokeyless.ErrUnexpectedOpcode, h.Body.Opcode) connError = conn.RespondError(h.ID, gokeyless.ErrUnexpectedOpcode) s.stats.logInvalid(requestBegin) continue default: connError = conn.RespondError(h.ID, gokeyless.ErrBadOpcode) s.stats.logInvalid(requestBegin) continue } if key, ok = s.Keys.Get(h.Body); !ok { log.Error(gokeyless.ErrKeyNotFound) connError = conn.RespondError(h.ID, gokeyless.ErrKeyNotFound) s.stats.logInvalid(requestBegin) continue } // Ensure we don't perform an ECDSA sign for an RSA request. switch h.Body.Opcode { case gokeyless.OpRSASignMD5SHA1, gokeyless.OpRSASignSHA1, gokeyless.OpRSASignSHA224, gokeyless.OpRSASignSHA256, gokeyless.OpRSASignSHA384, gokeyless.OpRSASignSHA512: if _, ok := key.Public().(*rsa.PublicKey); !ok { log.Errorf("%s: request is RSA, but key isn't\n", gokeyless.ErrCrypto) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) s.stats.logInvalid(requestBegin) continue } } sig, err := key.Sign(rand.Reader, h.Body.Payload, opts) if err != nil { log.Errorf("%s: Signing error: %v\n", gokeyless.ErrCrypto, err) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) s.stats.logInvalid(requestBegin) continue } connError = conn.Respond(h.ID, sig) s.stats.logRequest(requestBegin) } if connError == io.EOF { log.Debug("connection closed by client") } else { log.Errorf("connection error: %v\n", connError) } }
// NewRootCA creates a new RootCA object from unparsed cert and key byte // slices. key may be nil, and in this case NewRootCA will return a RootCA // without a signer. func NewRootCA(cert, key []byte, certExpiry time.Duration) (RootCA, error) { // Check to see if the Certificate file is a valid, self-signed Cert parsedCA, err := helpers.ParseSelfSignedCertificatePEM(cert) if err != nil { return RootCA{}, err } // Calculate the digest for our RootCACertificate digest := digest.FromBytes(cert) // Create a Pool with our RootCACertificate pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(cert) { return RootCA{}, fmt.Errorf("error while adding root CA cert to Cert Pool") } if len(key) == 0 { // This RootCA does not have a valid signer. return RootCA{Cert: cert, Digest: digest, Pool: pool}, nil } var ( passphraseStr string passphrase, passphrasePrev []byte priv crypto.Signer ) // Attempt two distinct passphrases, so we can do a hitless passphrase rotation if passphraseStr = os.Getenv(PassphraseENVVar); passphraseStr != "" { passphrase = []byte(passphraseStr) } if p := os.Getenv(PassphraseENVVarPrev); p != "" { passphrasePrev = []byte(p) } // Attempt to decrypt the current private-key with the passphrases provided priv, err = helpers.ParsePrivateKeyPEMWithPassword(key, passphrase) if err != nil { priv, err = helpers.ParsePrivateKeyPEMWithPassword(key, passphrasePrev) if err != nil { log.Debug("Malformed private key %v", err) return RootCA{}, err } } if err := ensureCertKeyMatch(parsedCA, priv.Public()); err != nil { return RootCA{}, err } signer, err := local.NewSigner(priv, parsedCA, cfsigner.DefaultSigAlgo(priv), SigningPolicy(certExpiry)) if err != nil { return RootCA{}, err } // If the key was loaded from disk unencrypted, but there is a passphrase set, // ensure it is encrypted, so it doesn't hit raft in plain-text keyBlock, _ := pem.Decode(key) if keyBlock == nil { // This RootCA does not have a valid signer. return RootCA{Cert: cert, Digest: digest, Pool: pool}, nil } if passphraseStr != "" && !x509.IsEncryptedPEMBlock(keyBlock) { key, err = EncryptECPrivateKey(key, passphraseStr) if err != nil { return RootCA{}, err } } return RootCA{Signer: signer, Key: key, Digest: digest, Cert: cert, Pool: pool}, nil }
func sign(stack_ *[]*asn1.CookStackElement, location string) error { stack := *stack_ if len(stack) < 3 { return fmt.Errorf("%vsign() called on stack with fewer than 3 elements", location) } data1, ok1 := stack[len(stack)-1].Value.([]byte) data2, ok2 := stack[len(stack)-2].Value.([]byte) data3, ok3 := stack[len(stack)-3].Value.([]byte) key1, ok4 := stack[len(stack)-1].Value.(crypto.Signer) key2, ok5 := stack[len(stack)-2].Value.(crypto.Signer) key3, ok6 := stack[len(stack)-3].Value.(crypto.Signer) algo1, ok7 := stack[len(stack)-1].Value.(map[string]interface{}) algo2, ok8 := stack[len(stack)-2].Value.(map[string]interface{}) algo3, ok9 := stack[len(stack)-3].Value.(map[string]interface{}) if !((ok1 || ok2 || ok3) && (ok4 || ok5 || ok6) && (ok7 || ok8 || ok9)) { return fmt.Errorf("%vsign() requires the top 3 elements of the stack to be a byte-array, a key and an AlgorithmIdentifier structure", location) } var data []byte if ok1 { data = data1 } if ok2 { data = data2 } if ok3 { data = data3 } var key crypto.Signer if ok4 { key = key1 } if ok5 { key = key2 } if ok6 { key = key3 } var algo map[string]interface{} if ok7 { algo = algo1 } if ok8 { algo = algo2 } if ok9 { algo = algo3 } algorithm, ok := algo["algorithm"] if !ok { return fmt.Errorf("%vsign() error: signatureAlgorithm has no \"algorithm\" member", location) } ok = false algooid := "" switch al := algorithm.(type) { case *asn1.Instance: ok = (al.Type() == "OBJECT_IDENTIFIER") if ok { algooid = al.JSON() algooid = algooid[2 : len(algooid)-1] // remove "$ and " } } if !ok { return fmt.Errorf("%vsign() error: \"algorithm\" not of type OBJECT IDENTIFIER", location) } var cryptohash crypto.Hash switch algooid { //md2WithRSAEncryption //case "1.2.840.113549.1.1.2": cryptohash = crypto.MD2 // md5WithRSAEncryption case "1.2.840.113549.1.1.4": cryptohash = crypto.MD5 // sha1WithRSAEncryption case "1.2.840.113549.1.1.5": cryptohash = crypto.SHA1 // id-dsa-with-sha1 case "1.2.840.10040.4.3": cryptohash = crypto.SHA1 // id-dsa-with-sha224 case "2.16.840.1.101.3.4.3.1": cryptohash = crypto.SHA224 // id-dsa-with-sha256 case "2.16.840.1.101.3.4.3.2": cryptohash = crypto.SHA256 // ecdsa-with-SHA1 case "1.2.840.10045.4.1": cryptohash = crypto.SHA1 // ecdsa-with-SHA224 case "1.2.840.10045.4.3.1": cryptohash = crypto.SHA224 // ecdsa-with-SHA256 case "1.2.840.10045.4.3.2": cryptohash = crypto.SHA256 // ecdsa-with-SHA384 case "1.2.840.10045.4.3.3": cryptohash = crypto.SHA384 // ecdsa-with-SHA512 case "1.2.840.10045.4.3.4": cryptohash = crypto.SHA512 // sha224WithRSAEncryption case "1.2.840.113549.1.1.14": cryptohash = crypto.SHA224 // sha256WithRSAEncryption case "1.2.840.113549.1.1.11": cryptohash = crypto.SHA256 // sha384WithRSAEncryption case "1.2.840.113549.1.1.12": cryptohash = crypto.SHA384 // sha512WithRSAEncryption case "1.2.840.113549.1.1.13": cryptohash = crypto.SHA512 default: return fmt.Errorf("%vsign() error: Unknown signature algorithm OID \"%v\"", location, algooid) } var hashhash hash.Hash hashhash = cryptohash.New() hashhash.Write(data) sig, err := key.Sign(rand.Reader, hashhash.Sum(nil), cryptohash) if err != nil { return fmt.Errorf("%vsign() error: %v", location, err) } *stack_ = append(stack[0:len(stack)-3], &asn1.CookStackElement{Value: sig}) return nil }
// NewRootCA creates a new RootCA object from unparsed PEM cert bundle and key byte // slices. key may be nil, and in this case NewRootCA will return a RootCA // without a signer. func NewRootCA(certBytes, keyBytes []byte, certExpiry time.Duration) (RootCA, error) { // Parse all the certificates in the cert bundle parsedCerts, err := helpers.ParseCertificatesPEM(certBytes) if err != nil { return RootCA{}, err } // Check to see if we have at least one valid cert if len(parsedCerts) < 1 { return RootCA{}, fmt.Errorf("no valid Root CA certificates found") } // Create a Pool with all of the certificates found pool := x509.NewCertPool() for _, cert := range parsedCerts { // Check to see if all of the certificates are valid, self-signed root CA certs if err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil { return RootCA{}, fmt.Errorf("error while validating Root CA Certificate: %v", err) } pool.AddCert(cert) } // Calculate the digest for our Root CA bundle digest := digest.FromBytes(certBytes) if len(keyBytes) == 0 { // This RootCA does not have a valid signer. return RootCA{Cert: certBytes, Digest: digest, Pool: pool}, nil } var ( passphraseStr string passphrase, passphrasePrev []byte priv crypto.Signer ) // Attempt two distinct passphrases, so we can do a hitless passphrase rotation if passphraseStr = os.Getenv(PassphraseENVVar); passphraseStr != "" { passphrase = []byte(passphraseStr) } if p := os.Getenv(PassphraseENVVarPrev); p != "" { passphrasePrev = []byte(p) } // Attempt to decrypt the current private-key with the passphrases provided priv, err = helpers.ParsePrivateKeyPEMWithPassword(keyBytes, passphrase) if err != nil { priv, err = helpers.ParsePrivateKeyPEMWithPassword(keyBytes, passphrasePrev) if err != nil { log.Debug("Malformed private key %v", err) return RootCA{}, err } } // We will always use the first certificate inside of the root bundle as the active one if err := ensureCertKeyMatch(parsedCerts[0], priv.Public()); err != nil { return RootCA{}, err } signer, err := local.NewSigner(priv, parsedCerts[0], cfsigner.DefaultSigAlgo(priv), SigningPolicy(certExpiry)) if err != nil { return RootCA{}, err } // If the key was loaded from disk unencrypted, but there is a passphrase set, // ensure it is encrypted, so it doesn't hit raft in plain-text keyBlock, _ := pem.Decode(keyBytes) if keyBlock == nil { // This RootCA does not have a valid signer. return RootCA{Cert: certBytes, Digest: digest, Pool: pool}, nil } if passphraseStr != "" && !x509.IsEncryptedPEMBlock(keyBlock) { keyBytes, err = EncryptECPrivateKey(keyBytes, passphraseStr) if err != nil { return RootCA{}, err } } return RootCA{Signer: signer, Key: keyBytes, Digest: digest, Cert: certBytes, Pool: pool}, nil }
// testKey performs and verifies all possible opaque private key operations. func testKey(priv crypto.Signer) (err error) { ptxt := []byte("Test Plaintext") r := rand.Reader hashes := []crypto.Hash{ crypto.MD5SHA1, crypto.SHA1, crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512, } for _, h := range hashes { var msg, sig []byte if h == crypto.MD5SHA1 { msg = append(hashPtxt(crypto.MD5, ptxt), hashPtxt(crypto.SHA1, ptxt)...) } else { msg = hashPtxt(h, ptxt) } if sig, err = priv.Sign(r, msg, h); err != nil { return } switch pub := priv.Public().(type) { case *rsa.PublicKey: if err = rsa.VerifyPKCS1v15(pub, h, msg, sig); err != nil { return } case *ecdsa.PublicKey: ecdsaSig := new(struct{ R, S *big.Int }) asn1.Unmarshal(sig, ecdsaSig) if !ecdsa.Verify(pub, msg, ecdsaSig.R, ecdsaSig.S) { return errors.New("ecdsa verify failed") } default: return errors.New("unknown public key type") } } if pub, ok := priv.Public().(*rsa.PublicKey); ok { var c, m []byte if c, err = rsa.EncryptPKCS1v15(r, pub, ptxt); err != nil { return } var decrypter crypto.Decrypter if decrypter, ok = priv.(crypto.Decrypter); !ok { return errors.New("rsa public key but cannot decrypt") } if m, err = decrypter.Decrypt(r, c, &rsa.PKCS1v15DecryptOptions{}); err != nil { return } if bytes.Compare(ptxt, m) != 0 { return errors.New("rsa decrypt failed") } if m, err = decrypter.Decrypt(r, c, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: len(ptxt)}); err != nil { return } if bytes.Compare(ptxt, m) != 0 { return errors.New("rsa decrypt failed") } if m, err = decrypter.Decrypt(r, c, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: len(ptxt) + 1}); err != nil { return } if bytes.Compare(ptxt, m) == 0 { return errors.New("rsa decrypt suceeded despite incorrect SessionKeyLen") } } return nil }