This repository has been archived by the owner on Mar 24, 2021. It is now read-only.
forked from geoko86/pkcs7
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix hardcoded signature algorithm for verifying signers
Since Go 1.10, the SignatureAlgorithm is now validated against the public key type. It was "working" before because the Amazon key used DSA with SHA1, and so the RSA/DSA mismatch didn't matter since the SHA1 hash type did. This uses some unexported code from `crypto/x509` that looks up a signature algorithm for a given `pxix.AlgorithmIdentifier` Fixes fullsailor#27 Fixes fullsailor#28 Fixes fullsailor#29
- Loading branch information
1 parent
a2fc7ee
commit fa02d36
Showing
2 changed files
with
132 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// 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"` | ||
} | ||
|
||
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, asn1.NullBytes) || | ||
!params.MGF.Algorithm.Equal(oidMGF1) || | ||
!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || | ||
!bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.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 | ||
} |