|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 */ |
|
5 |
|
6 #include "pkcs1sig.h" |
|
7 #include "hasht.h" |
|
8 #include "secerr.h" |
|
9 #include "secasn1t.h" |
|
10 #include "secoid.h" |
|
11 |
|
12 typedef struct pkcs1PrefixStr pkcs1Prefix; |
|
13 struct pkcs1PrefixStr { |
|
14 unsigned int len; |
|
15 PRUint8 *data; |
|
16 }; |
|
17 |
|
18 typedef struct pkcs1PrefixesStr pkcs1Prefixes; |
|
19 struct pkcs1PrefixesStr { |
|
20 unsigned int digestLen; |
|
21 pkcs1Prefix prefixWithParams; |
|
22 pkcs1Prefix prefixWithoutParams; |
|
23 }; |
|
24 |
|
25 /* The value for SGN_PKCS1_DIGESTINFO_MAX_PREFIX_LEN_EXCLUDING_OID is based on |
|
26 * the possible prefix encodings as explained below. |
|
27 */ |
|
28 #define MAX_PREFIX_LEN_EXCLUDING_OID 10 |
|
29 |
|
30 static SECStatus |
|
31 encodePrefix(const SECOidData *hashOid, unsigned int digestLen, |
|
32 pkcs1Prefix *prefix, PRBool withParams) |
|
33 { |
|
34 /* with params coding is: |
|
35 * Sequence (2 bytes) { |
|
36 * Sequence (2 bytes) { |
|
37 * Oid (2 bytes) { |
|
38 * Oid value (derOid->oid.len) |
|
39 * } |
|
40 * NULL (2 bytes) |
|
41 * } |
|
42 * OCTECT (2 bytes); |
|
43 * |
|
44 * without params coding is: |
|
45 * Sequence (2 bytes) { |
|
46 * Sequence (2 bytes) { |
|
47 * Oid (2 bytes) { |
|
48 * Oid value (derOid->oid.len) |
|
49 * } |
|
50 * } |
|
51 * OCTECT (2 bytes); |
|
52 */ |
|
53 |
|
54 unsigned int innerSeqLen = 2 + hashOid->oid.len; |
|
55 unsigned int outerSeqLen = 2 + innerSeqLen + 2 + digestLen; |
|
56 unsigned int extra = 0; |
|
57 |
|
58 if (withParams) { |
|
59 innerSeqLen += 2; |
|
60 outerSeqLen += 2; |
|
61 extra = 2; |
|
62 } |
|
63 |
|
64 if (innerSeqLen >= 128 || |
|
65 outerSeqLen >= 128 || |
|
66 (outerSeqLen + 2 - digestLen) > |
|
67 (MAX_PREFIX_LEN_EXCLUDING_OID + hashOid->oid.len)) { |
|
68 /* this is actually a library failure, It shouldn't happen */ |
|
69 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
70 return SECFailure; |
|
71 } |
|
72 |
|
73 prefix->len = 6 + hashOid->oid.len + extra + 2; |
|
74 prefix->data = PORT_Alloc(prefix->len); |
|
75 if (!prefix->data) { |
|
76 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
77 return SECFailure; |
|
78 } |
|
79 |
|
80 prefix->data[0] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED; |
|
81 prefix->data[1] = outerSeqLen; |
|
82 prefix->data[2] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED; |
|
83 prefix->data[3] = innerSeqLen; |
|
84 prefix->data[4] = SEC_ASN1_OBJECT_ID; |
|
85 prefix->data[5] = hashOid->oid.len; |
|
86 PORT_Memcpy(&prefix->data[6], hashOid->oid.data, hashOid->oid.len); |
|
87 if (withParams) { |
|
88 prefix->data[6 + hashOid->oid.len] = SEC_ASN1_NULL; |
|
89 prefix->data[6 + hashOid->oid.len + 1] = 0; |
|
90 } |
|
91 prefix->data[6 + hashOid->oid.len + extra] = SEC_ASN1_OCTET_STRING; |
|
92 prefix->data[6 + hashOid->oid.len + extra + 1] = digestLen; |
|
93 |
|
94 return SECSuccess; |
|
95 } |
|
96 |
|
97 SECStatus |
|
98 _SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg, |
|
99 const SECItem* digest, |
|
100 const SECItem* dataRecoveredFromSignature, |
|
101 PRBool unsafeAllowMissingParameters) |
|
102 { |
|
103 SECOidData *hashOid; |
|
104 pkcs1Prefixes pp; |
|
105 const pkcs1Prefix* expectedPrefix; |
|
106 SECStatus rv, rv2, rv3; |
|
107 |
|
108 if (!digest || !digest->data || |
|
109 !dataRecoveredFromSignature || !dataRecoveredFromSignature->data) { |
|
110 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
111 return SECFailure; |
|
112 } |
|
113 |
|
114 hashOid = SECOID_FindOIDByTag(digestAlg); |
|
115 if (hashOid == NULL) { |
|
116 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
117 return SECFailure; |
|
118 } |
|
119 |
|
120 pp.digestLen = digest->len; |
|
121 pp.prefixWithParams.data = NULL; |
|
122 pp.prefixWithoutParams.data = NULL; |
|
123 |
|
124 rv2 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithParams, PR_TRUE); |
|
125 rv3 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithoutParams, PR_FALSE); |
|
126 |
|
127 rv = SECSuccess; |
|
128 if (rv2 != SECSuccess || rv3 != SECSuccess) { |
|
129 rv = SECFailure; |
|
130 } |
|
131 |
|
132 if (rv == SECSuccess) { |
|
133 /* We don't attempt to avoid timing attacks on these comparisons because |
|
134 * signature verification is a public key operation, not a private key |
|
135 * operation. |
|
136 */ |
|
137 |
|
138 if (dataRecoveredFromSignature->len == |
|
139 pp.prefixWithParams.len + pp.digestLen) { |
|
140 expectedPrefix = &pp.prefixWithParams; |
|
141 } else if (unsafeAllowMissingParameters && |
|
142 dataRecoveredFromSignature->len == |
|
143 pp.prefixWithoutParams.len + pp.digestLen) { |
|
144 expectedPrefix = &pp.prefixWithoutParams; |
|
145 } else { |
|
146 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
|
147 rv = SECFailure; |
|
148 } |
|
149 } |
|
150 |
|
151 if (rv == SECSuccess) { |
|
152 if (memcmp(dataRecoveredFromSignature->data, expectedPrefix->data, |
|
153 expectedPrefix->len) || |
|
154 memcmp(dataRecoveredFromSignature->data + expectedPrefix->len, |
|
155 digest->data, digest->len)) { |
|
156 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
|
157 rv = SECFailure; |
|
158 } |
|
159 } |
|
160 |
|
161 if (pp.prefixWithParams.data) { |
|
162 PORT_Free(pp.prefixWithParams.data); |
|
163 } |
|
164 if (pp.prefixWithoutParams.data) { |
|
165 PORT_Free(pp.prefixWithoutParams.data); |
|
166 } |
|
167 |
|
168 return rv; |
|
169 } |