1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the go/golang LICENSE file.
4
5package pkcs7
6
7// These are private constants and functions from the crypto/x509 package that
8// are useful when dealing with signatures verified by x509 certificates
9
10import (
11	"bytes"
12	"crypto"
13	"crypto/x509"
14	"crypto/x509/pkix"
15	"encoding/asn1"
16)
17
18var (
19	oidSignatureMD2WithRSA      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
20	oidSignatureMD5WithRSA      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
21	oidSignatureSHA1WithRSA     = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
22	oidSignatureSHA256WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
23	oidSignatureSHA384WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
24	oidSignatureSHA512WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
25	oidSignatureRSAPSS          = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
26	oidSignatureDSAWithSHA1     = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
27	oidSignatureDSAWithSHA256   = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
28	oidSignatureECDSAWithSHA1   = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
29	oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
30	oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
31	oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
32
33	oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
34	oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
35	oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
36
37	oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
38
39	// oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
40	// but it's specified by ISO. Microsoft's makecert.exe has been known
41	// to produce certificates with this OID.
42	oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
43)
44
45var signatureAlgorithmDetails = []struct {
46	algo       x509.SignatureAlgorithm
47	name       string
48	oid        asn1.ObjectIdentifier
49	pubKeyAlgo x509.PublicKeyAlgorithm
50	hash       crypto.Hash
51}{
52	{x509.MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */},
53	{x509.MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, x509.RSA, crypto.MD5},
54	{x509.SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
55	{x509.SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
56	{x509.SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256},
57	{x509.SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384},
58	{x509.SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512},
59	{x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA256},
60	{x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA384},
61	{x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA512},
62	{x509.DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1},
63	{x509.DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256},
64	{x509.ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1},
65	{x509.ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256},
66	{x509.ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384},
67	{x509.ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
68}
69
70// pssParameters reflects the parameters in an AlgorithmIdentifier that
71// specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3
72type pssParameters struct {
73	// The following three fields are not marked as
74	// optional because the default values specify SHA-1,
75	// which is no longer suitable for use in signatures.
76	Hash         pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
77	MGF          pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
78	SaltLength   int                      `asn1:"explicit,tag:2"`
79	TrailerField int                      `asn1:"optional,explicit,tag:3,default:1"`
80}
81
82// asn1.NullBytes is not available prior to Go 1.9
83var nullBytes = []byte{5, 0}
84
85func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) x509.SignatureAlgorithm {
86	if !ai.Algorithm.Equal(oidSignatureRSAPSS) {
87		for _, details := range signatureAlgorithmDetails {
88			if ai.Algorithm.Equal(details.oid) {
89				return details.algo
90			}
91		}
92		return x509.UnknownSignatureAlgorithm
93	}
94
95	// RSA PSS is special because it encodes important parameters
96	// in the Parameters.
97
98	var params pssParameters
99	if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, &params); err != nil {
100		return x509.UnknownSignatureAlgorithm
101	}
102
103	var mgf1HashFunc pkix.AlgorithmIdentifier
104	if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil {
105		return x509.UnknownSignatureAlgorithm
106	}
107
108	// PSS is greatly overburdened with options. This code forces
109	// them into three buckets by requiring that the MGF1 hash
110	// function always match the message hash function (as
111	// recommended in
112	// https://tools.ietf.org/html/rfc3447#section-8.1), that the
113	// salt length matches the hash length, and that the trailer
114	// field has the default value.
115	if !bytes.Equal(params.Hash.Parameters.FullBytes, nullBytes) ||
116		!params.MGF.Algorithm.Equal(oidMGF1) ||
117		!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
118		!bytes.Equal(mgf1HashFunc.Parameters.FullBytes, nullBytes) ||
119		params.TrailerField != 1 {
120		return x509.UnknownSignatureAlgorithm
121	}
122
123	switch {
124	case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32:
125		return x509.SHA256WithRSAPSS
126	case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48:
127		return x509.SHA384WithRSAPSS
128	case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64:
129		return x509.SHA512WithRSAPSS
130	}
131
132	return x509.UnknownSignatureAlgorithm
133}
134