diff options
Diffstat (limited to 'libgo/go/crypto/x509/x509.go')
-rw-r--r-- | libgo/go/crypto/x509/x509.go | 276 |
1 files changed, 227 insertions, 49 deletions
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index d9288bb30e..949ce01856 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -36,6 +36,12 @@ type pkixPublicKey struct { // ParsePKIXPublicKey parses a DER encoded public key. These values are // typically found in PEM blocks with "BEGIN PUBLIC KEY". +// +// Supported key types include RSA, DSA, and ECDSA. Unknown key +// types result in an error. +// +// On success, pub will be of type *rsa.PublicKey, *dsa.PublicKey, +// or *ecdsa.PublicKey. func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) { var pki publicKeyInfo if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil { @@ -61,9 +67,8 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith return nil, pkix.AlgorithmIdentifier{}, err } publicKeyAlgorithm.Algorithm = oidPublicKeyRSA - // This is a NULL parameters value which is technically - // superfluous, but most other code includes it and, by - // doing this, we match their public key hashes. + // This is a NULL parameters value which is required by + // https://tools.ietf.org/html/rfc3279#section-2.3.1. publicKeyAlgorithm.Parameters = asn1.RawValue{ Tag: 5, } @@ -120,7 +125,7 @@ type certificate struct { type tbsCertificate struct { Raw asn1.RawContent - Version int `asn1:"optional,explicit,default:1,tag:0"` + Version int `asn1:"optional,explicit,default:0,tag:0"` SerialNumber *big.Int SignatureAlgorithm pkix.AlgorithmIdentifier Issuer asn1.RawValue @@ -173,21 +178,36 @@ const ( ECDSAWithSHA256 ECDSAWithSHA384 ECDSAWithSHA512 + SHA256WithRSAPSS + SHA384WithRSAPSS + SHA512WithRSAPSS ) +func (algo SignatureAlgorithm) isRSAPSS() bool { + switch algo { + case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS: + return true + default: + return false + } +} + var algoName = [...]string{ - MD2WithRSA: "MD2-RSA", - MD5WithRSA: "MD5-RSA", - SHA1WithRSA: "SHA1-RSA", - SHA256WithRSA: "SHA256-RSA", - SHA384WithRSA: "SHA384-RSA", - SHA512WithRSA: "SHA512-RSA", - DSAWithSHA1: "DSA-SHA1", - DSAWithSHA256: "DSA-SHA256", - ECDSAWithSHA1: "ECDSA-SHA1", - ECDSAWithSHA256: "ECDSA-SHA256", - ECDSAWithSHA384: "ECDSA-SHA384", - ECDSAWithSHA512: "ECDSA-SHA512", + MD2WithRSA: "MD2-RSA", + MD5WithRSA: "MD5-RSA", + SHA1WithRSA: "SHA1-RSA", + SHA256WithRSA: "SHA256-RSA", + SHA384WithRSA: "SHA384-RSA", + SHA512WithRSA: "SHA512-RSA", + SHA256WithRSAPSS: "SHA256-RSAPSS", + SHA384WithRSAPSS: "SHA384-RSAPSS", + SHA512WithRSAPSS: "SHA512-RSAPSS", + DSAWithSHA1: "DSA-SHA1", + DSAWithSHA256: "DSA-SHA256", + ECDSAWithSHA1: "ECDSA-SHA1", + ECDSAWithSHA256: "ECDSA-SHA256", + ECDSAWithSHA384: "ECDSA-SHA384", + ECDSAWithSHA512: "ECDSA-SHA512", } func (algo SignatureAlgorithm) String() string { @@ -263,12 +283,24 @@ var ( oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} + oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} - oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2} + oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} + + oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} + oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} + oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} + + oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8} + + // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA + // but it's specified by ISO. Microsoft's makecert.exe has been known + // to produce certificates with this OID. + oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} ) var signatureAlgorithmDetails = []struct { @@ -280,9 +312,13 @@ var signatureAlgorithmDetails = []struct { {MD2WithRSA, oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */}, {MD5WithRSA, oidSignatureMD5WithRSA, RSA, crypto.MD5}, {SHA1WithRSA, oidSignatureSHA1WithRSA, RSA, crypto.SHA1}, + {SHA1WithRSA, oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1}, {SHA256WithRSA, oidSignatureSHA256WithRSA, RSA, crypto.SHA256}, {SHA384WithRSA, oidSignatureSHA384WithRSA, RSA, crypto.SHA384}, {SHA512WithRSA, oidSignatureSHA512WithRSA, RSA, crypto.SHA512}, + {SHA256WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA256}, + {SHA384WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA384}, + {SHA512WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA512}, {DSAWithSHA1, oidSignatureDSAWithSHA1, DSA, crypto.SHA1}, {DSAWithSHA256, oidSignatureDSAWithSHA256, DSA, crypto.SHA256}, {ECDSAWithSHA1, oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1}, @@ -291,12 +327,115 @@ var signatureAlgorithmDetails = []struct { {ECDSAWithSHA512, oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512}, } -func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm { - for _, details := range signatureAlgorithmDetails { - if oid.Equal(details.oid) { - return details.algo +// pssParameters reflects the parameters in an AlgorithmIdentifier that +// specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3 +type pssParameters struct { + // The following three fields are not marked as + // optional because the default values specify SHA-1, + // which is no longer suitable for use in signatures. + Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"` + MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"` + SaltLength int `asn1:"explicit,tag:2"` + TrailerField int `asn1:"optional,explicit,tag:3,default:1"` +} + +// rsaPSSParameters returns an asn1.RawValue suitable for use as the Parameters +// in an AlgorithmIdentifier that specifies RSA PSS. +func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue { + var hashOID asn1.ObjectIdentifier + + switch hashFunc { + case crypto.SHA256: + hashOID = oidSHA256 + case crypto.SHA384: + hashOID = oidSHA384 + case crypto.SHA512: + hashOID = oidSHA512 + } + + params := pssParameters{ + Hash: pkix.AlgorithmIdentifier{ + Algorithm: hashOID, + Parameters: asn1.RawValue{ + Tag: 5, /* ASN.1 NULL */ + }, + }, + MGF: pkix.AlgorithmIdentifier{ + Algorithm: oidMGF1, + }, + SaltLength: hashFunc.Size(), + TrailerField: 1, + } + + mgf1Params := pkix.AlgorithmIdentifier{ + Algorithm: hashOID, + Parameters: asn1.RawValue{ + Tag: 5, /* ASN.1 NULL */ + }, + } + + var err error + params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params) + if err != nil { + panic(err) + } + + serialized, err := asn1.Marshal(params) + if err != nil { + panic(err) + } + + return asn1.RawValue{FullBytes: serialized} +} + +func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm { + if !ai.Algorithm.Equal(oidSignatureRSAPSS) { + for _, details := range signatureAlgorithmDetails { + if ai.Algorithm.Equal(details.oid) { + return details.algo + } } + return UnknownSignatureAlgorithm + } + + // RSA PSS is special because it encodes important parameters + // in the Parameters. + + var params pssParameters + if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil { + return UnknownSignatureAlgorithm + } + + var mgf1HashFunc pkix.AlgorithmIdentifier + if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil { + return UnknownSignatureAlgorithm + } + + // PSS is greatly overburdened with options. This code forces + // them into three buckets by requiring that the MGF1 hash + // function always match the message hash function (as + // recommended in + // https://tools.ietf.org/html/rfc3447#section-8.1), that the + // salt length matches the hash length, and that the trailer + // field has the default value. + asn1NULL := []byte{0x05, 0x00} + if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1NULL) || + !params.MGF.Algorithm.Equal(oidMGF1) || + !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || + !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1NULL) || + params.TrailerField != 1 { + return UnknownSignatureAlgorithm } + + switch { + case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32: + return SHA256WithRSAPSS + case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48: + return SHA384WithRSAPSS + case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64: + return SHA512WithRSAPSS + } + return UnknownSignatureAlgorithm } @@ -635,7 +774,7 @@ var entrustBrokenSPKI = []byte{ // CheckSignatureFrom verifies that the signature on c is a valid signature // from parent. -func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) { +func (c *Certificate) CheckSignatureFrom(parent *Certificate) error { // RFC 5280, 4.2.1.9: // "If the basic constraints extension is not present in a version 3 // certificate, or the extension is present but the cA boolean is not @@ -663,7 +802,7 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) { // CheckSignature verifies that signature is a valid signature over signed from // c's public key. -func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err error) { +func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error { return checkSignature(algo, signed, signature, c.PublicKey) } @@ -675,11 +814,11 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey switch algo { case SHA1WithRSA, DSAWithSHA1, ECDSAWithSHA1: hashType = crypto.SHA1 - case SHA256WithRSA, DSAWithSHA256, ECDSAWithSHA256: + case SHA256WithRSA, SHA256WithRSAPSS, DSAWithSHA256, ECDSAWithSHA256: hashType = crypto.SHA256 - case SHA384WithRSA, ECDSAWithSHA384: + case SHA384WithRSA, SHA384WithRSAPSS, ECDSAWithSHA384: hashType = crypto.SHA384 - case SHA512WithRSA, ECDSAWithSHA512: + case SHA512WithRSA, SHA512WithRSAPSS, ECDSAWithSHA512: hashType = crypto.SHA512 case MD2WithRSA, MD5WithRSA: return InsecureAlgorithmError(algo) @@ -697,7 +836,11 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey switch pub := publicKey.(type) { case *rsa.PublicKey: - return rsa.VerifyPKCS1v15(pub, hashType, digest, signature) + if algo.isRSAPSS() { + return rsa.VerifyPSS(pub, hashType, digest, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}) + } else { + return rsa.VerifyPKCS1v15(pub, hashType, digest, signature) + } case *dsa.PublicKey: dsaSig := new(dsaSignature) if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil { @@ -731,8 +874,8 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey } // CheckCRLSignature checks that the signature in crl is from c. -func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err error) { - algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm) +func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error { + algo := getSignatureAlgorithmFromAI(crl.SignatureAlgorithm) return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign()) } @@ -781,10 +924,19 @@ type distributionPointName struct { RelativeName pkix.RDNSequence `asn1:"optional,tag:1"` } +// asn1Null is the ASN.1 encoding of a NULL value. +var asn1Null = []byte{5, 0} + func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) { asn1Data := keyData.PublicKey.RightAlign() switch algo { case RSA: + // RSA public keys must have a NULL in the parameters + // (https://tools.ietf.org/html/rfc3279#section-2.3.1). + if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1Null) { + return nil, errors.New("x509: RSA key missing NULL parameters") + } + p := new(rsaPublicKey) rest, err := asn1.Unmarshal(asn1Data, p) if err != nil { @@ -931,7 +1083,7 @@ func parseCertificate(in *certificate) (*Certificate, error) { out.Signature = in.SignatureValue.RightAlign() out.SignatureAlgorithm = - getSignatureAlgorithmFromOID(in.TBSCertificate.SignatureAlgorithm.Algorithm) + getSignatureAlgorithmFromAI(in.TBSCertificate.SignatureAlgorithm) out.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm) @@ -1127,7 +1279,7 @@ func parseCertificate(in *certificate) (*Certificate, error) { if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil { return nil, err } else if len(rest) != 0 { - return nil, errors.New("x509: trailing data after X.509 authority key-id") + return nil, errors.New("x509: trailing data after X.509 key-id") } out.SubjectKeyId = keyid @@ -1539,6 +1691,9 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori err = errors.New("x509: cannot sign with hash function requested") return } + if requestedSigAlgo.isRSAPSS() { + sigAlgo.Parameters = rsaPSSParameters(hashFunc) + } found = true break } @@ -1571,6 +1726,10 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } + if template.SerialNumber == nil { + return nil, errors.New("x509: no SerialNumber given") + } + hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) if err != nil { return nil, err @@ -1581,21 +1740,21 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv return nil, err } - if len(parent.SubjectKeyId) > 0 { - template.AuthorityKeyId = parent.SubjectKeyId - } - - extensions, err := buildExtensions(template) + asn1Issuer, err := subjectBytes(parent) if err != nil { return } - asn1Issuer, err := subjectBytes(parent) + asn1Subject, err := subjectBytes(template) if err != nil { return } - asn1Subject, err := subjectBytes(template) + if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 { + template.AuthorityKeyId = parent.SubjectKeyId + } + + extensions, err := buildExtensions(template) if err != nil { return } @@ -1623,8 +1782,17 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv h.Write(tbsCertContents) digest := h.Sum(nil) + var signerOpts crypto.SignerOpts + signerOpts = hashFunc + if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() { + signerOpts = &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthEqualsHash, + Hash: hashFunc, + } + } + var signature []byte - signature, err = key.Sign(rand, digest, hashFunc) + signature, err = key.Sign(rand, digest, signerOpts) if err != nil { return } @@ -1648,7 +1816,7 @@ var pemType = "X509 CRL" // encoded CRLs will appear where they should be DER encoded, so this function // will transparently handle PEM encoding as long as there isn't any leading // garbage. -func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) { +func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) { if bytes.HasPrefix(crlBytes, pemCRLPrefix) { block, _ := pem.Decode(crlBytes) if block != nil && block.Type == pemType { @@ -1659,8 +1827,8 @@ func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) { } // ParseDERCRL parses a DER encoded CRL from the given bytes. -func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) { - certList = new(pkix.CertificateList) +func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) { + certList := new(pkix.CertificateList) if rest, err := asn1.Unmarshal(derBytes, certList); err != nil { return nil, err } else if len(rest) != 0 { @@ -1682,13 +1850,20 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [ return nil, err } + // Force revocation times to UTC per RFC 5280. + revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts)) + for i, rc := range revokedCerts { + rc.RevocationTime = rc.RevocationTime.UTC() + revokedCertsUTC[i] = rc + } + tbsCertList := pkix.TBSCertificateList{ Version: 1, Signature: signatureAlgorithm, Issuer: c.Subject.ToRDNSequence(), ThisUpdate: now.UTC(), NextUpdate: expiry.UTC(), - RevokedCertificates: revokedCerts, + RevokedCertificates: revokedCertsUTC, } // Authority Key Id @@ -1790,12 +1965,15 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) { var rawAttributes []asn1.RawValue b, err := asn1.Marshal(attributes) + if err != nil { + return nil, err + } rest, err := asn1.Unmarshal(b, &rawAttributes) if err != nil { return nil, err } if len(rest) != 0 { - return nil, errors.New("x509: failed to unmarshall raw CSR Attributes") + return nil, errors.New("x509: failed to unmarshal raw CSR Attributes") } return rawAttributes, nil } @@ -1847,8 +2025,8 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) return ret, nil } -// CreateCertificateRequest creates a new certificate based on a template. The -// following members of template are used: Subject, Attributes, +// CreateCertificateRequest creates a new certificate request based on a template. +// The following members of template are used: Subject, Attributes, // SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses. // The private key is the private key of the signer. // @@ -2026,7 +2204,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error RawSubject: in.TBSCSR.Subject.FullBytes, Signature: in.SignatureValue.RightAlign(), - SignatureAlgorithm: getSignatureAlgorithmFromOID(in.SignatureAlgorithm.Algorithm), + SignatureAlgorithm: getSignatureAlgorithmFromAI(in.SignatureAlgorithm), PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm), @@ -2065,7 +2243,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error return out, nil } -// CheckSignature verifies that the signature on c is a valid signature -func (c *CertificateRequest) CheckSignature() (err error) { +// CheckSignature reports whether the signature on c is valid. +func (c *CertificateRequest) CheckSignature() error { return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey) } |