// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the go/golang LICENSE file. package pkcs7 // These are private constants and functions from the crypto/x509 package that // are useful when dealing with signatures verified by x509 certificates import ( "bytes" "crypto" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" ) var ( oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} 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, 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 { algo x509.SignatureAlgorithm name string oid asn1.ObjectIdentifier pubKeyAlgo x509.PublicKeyAlgorithm hash crypto.Hash }{ {x509.MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */}, {x509.MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, x509.RSA, crypto.MD5}, {x509.SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1}, {x509.SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, x509.RSA, crypto.SHA1}, {x509.SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256}, {x509.SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384}, {x509.SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512}, {x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA256}, {x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA384}, {x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA512}, {x509.DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1}, {x509.DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256}, {x509.ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1}, {x509.ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256}, {x509.ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384}, {x509.ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512}, } // 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"` } // asn1.NullBytes is not available prior to Go 1.9 var nullBytes = []byte{5, 0} func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) x509.SignatureAlgorithm { if !ai.Algorithm.Equal(oidSignatureRSAPSS) { for _, details := range signatureAlgorithmDetails { if ai.Algorithm.Equal(details.oid) { return details.algo } } return x509.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 x509.UnknownSignatureAlgorithm } var mgf1HashFunc pkix.AlgorithmIdentifier if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil { return x509.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. if !bytes.Equal(params.Hash.Parameters.FullBytes, nullBytes) || !params.MGF.Algorithm.Equal(oidMGF1) || !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, nullBytes) || params.TrailerField != 1 { return x509.UnknownSignatureAlgorithm } switch { case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32: return x509.SHA256WithRSAPSS case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48: return x509.SHA384WithRSAPSS case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64: return x509.SHA512WithRSAPSS } return x509.UnknownSignatureAlgorithm }