|
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 #ifdef XP_WIN |
|
6 #ifndef WIN32_LEAN_AND_MEAN |
|
7 #define WIN32_LEAN_AND_MEAN |
|
8 #endif |
|
9 #endif |
|
10 |
|
11 #include <stdlib.h> |
|
12 #include "cryptox.h" |
|
13 |
|
14 #if defined(MAR_NSS) |
|
15 |
|
16 /** |
|
17 * Loads the public key for the specified cert name from the NSS store. |
|
18 * |
|
19 * @param certName The cert name to find. |
|
20 * @param publicKey Out parameter for the public key to use. |
|
21 * @param cert Out parameter for the certificate to use. |
|
22 * @return CryptoX_Success on success, CryptoX_Error on error. |
|
23 */ |
|
24 CryptoX_Result |
|
25 NSS_LoadPublicKey(const char *certNickname, |
|
26 SECKEYPublicKey **publicKey, |
|
27 CERTCertificate **cert) |
|
28 { |
|
29 secuPWData pwdata = { PW_NONE, 0 }; |
|
30 if (!cert || !publicKey || !cert) { |
|
31 return CryptoX_Error; |
|
32 } |
|
33 |
|
34 /* Get the cert and embedded public key out of the database */ |
|
35 *cert = PK11_FindCertFromNickname(certNickname, &pwdata); |
|
36 if (!*cert) { |
|
37 return CryptoX_Error; |
|
38 } |
|
39 *publicKey = CERT_ExtractPublicKey(*cert); |
|
40 if (!*publicKey) { |
|
41 CERT_DestroyCertificate(*cert); |
|
42 return CryptoX_Error; |
|
43 } |
|
44 return CryptoX_Success; |
|
45 } |
|
46 |
|
47 CryptoX_Result |
|
48 NSS_VerifyBegin(VFYContext **ctx, |
|
49 SECKEYPublicKey * const *publicKey) |
|
50 { |
|
51 SECStatus status; |
|
52 if (!ctx || !publicKey || !*publicKey) { |
|
53 return CryptoX_Error; |
|
54 } |
|
55 |
|
56 /* Check that the key length is large enough for our requirements */ |
|
57 if ((SECKEY_PublicKeyStrength(*publicKey) * 8) < |
|
58 XP_MIN_SIGNATURE_LEN_IN_BYTES) { |
|
59 fprintf(stderr, "ERROR: Key length must be >= %d bytes\n", |
|
60 XP_MIN_SIGNATURE_LEN_IN_BYTES); |
|
61 return CryptoX_Error; |
|
62 } |
|
63 |
|
64 *ctx = VFY_CreateContext(*publicKey, NULL, |
|
65 SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL); |
|
66 if (*ctx == NULL) { |
|
67 return CryptoX_Error; |
|
68 } |
|
69 |
|
70 status = VFY_Begin(*ctx); |
|
71 return SECSuccess == status ? CryptoX_Success : CryptoX_Error; |
|
72 } |
|
73 |
|
74 /** |
|
75 * Verifies if a verify context matches the passed in signature. |
|
76 * |
|
77 * @param ctx The verify context that the signature should match. |
|
78 * @param signature The signature to match. |
|
79 * @param signatureLen The length of the signature. |
|
80 * @return CryptoX_Success on success, CryptoX_Error on error. |
|
81 */ |
|
82 CryptoX_Result |
|
83 NSS_VerifySignature(VFYContext * const *ctx, |
|
84 const unsigned char *signature, |
|
85 unsigned int signatureLen) |
|
86 { |
|
87 SECItem signedItem; |
|
88 SECStatus status; |
|
89 if (!ctx || !signature || !*ctx) { |
|
90 return CryptoX_Error; |
|
91 } |
|
92 |
|
93 signedItem.len = signatureLen; |
|
94 signedItem.data = (unsigned char*)signature; |
|
95 status = VFY_EndWithSignature(*ctx, &signedItem); |
|
96 return SECSuccess == status ? CryptoX_Success : CryptoX_Error; |
|
97 } |
|
98 |
|
99 #elif defined(XP_WIN) |
|
100 /** |
|
101 * Verifies if a signature + public key matches a hash context. |
|
102 * |
|
103 * @param hash The hash context that the signature should match. |
|
104 * @param pubKey The public key to use on the signature. |
|
105 * @param signature The signature to check. |
|
106 * @param signatureLen The length of the signature. |
|
107 * @return CryptoX_Success on success, CryptoX_Error on error. |
|
108 */ |
|
109 CryptoX_Result |
|
110 CyprtoAPI_VerifySignature(HCRYPTHASH *hash, |
|
111 HCRYPTKEY *pubKey, |
|
112 const BYTE *signature, |
|
113 DWORD signatureLen) |
|
114 { |
|
115 DWORD i; |
|
116 BOOL result; |
|
117 /* Windows APIs expect the bytes in the signature to be in little-endian |
|
118 * order, but we write the signature in big-endian order. Other APIs like |
|
119 * NSS and OpenSSL expect big-endian order. |
|
120 */ |
|
121 BYTE *signatureReversed; |
|
122 if (!hash || !pubKey || !signature || signatureLen < 1) { |
|
123 return CryptoX_Error; |
|
124 } |
|
125 |
|
126 signatureReversed = malloc(signatureLen); |
|
127 if (!signatureReversed) { |
|
128 return CryptoX_Error; |
|
129 } |
|
130 |
|
131 for (i = 0; i < signatureLen; i++) { |
|
132 signatureReversed[i] = signature[signatureLen - 1 - i]; |
|
133 } |
|
134 result = CryptVerifySignature(*hash, signatureReversed, |
|
135 signatureLen, *pubKey, NULL, 0); |
|
136 free(signatureReversed); |
|
137 return result ? CryptoX_Success : CryptoX_Error; |
|
138 } |
|
139 |
|
140 /** |
|
141 * Obtains the public key for the passed in cert data |
|
142 * |
|
143 * @param provider The cyrto provider |
|
144 * @param certData Data of the certificate to extract the public key from |
|
145 * @param sizeOfCertData The size of the certData buffer |
|
146 * @param certStore Pointer to the handle of the certificate store to use |
|
147 * @param CryptoX_Success on success |
|
148 */ |
|
149 CryptoX_Result |
|
150 CryptoAPI_LoadPublicKey(HCRYPTPROV provider, |
|
151 BYTE *certData, |
|
152 DWORD sizeOfCertData, |
|
153 HCRYPTKEY *publicKey, |
|
154 HCERTSTORE *certStore) |
|
155 { |
|
156 CRYPT_DATA_BLOB blob; |
|
157 CERT_CONTEXT *context; |
|
158 if (!provider || !certData || !publicKey || !certStore) { |
|
159 return CryptoX_Error; |
|
160 } |
|
161 |
|
162 blob.cbData = sizeOfCertData; |
|
163 blob.pbData = certData; |
|
164 if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, |
|
165 CERT_QUERY_CONTENT_FLAG_CERT, |
|
166 CERT_QUERY_FORMAT_FLAG_BINARY, |
|
167 0, NULL, NULL, NULL, |
|
168 certStore, NULL, (const void **)&context)) { |
|
169 return CryptoX_Error; |
|
170 } |
|
171 |
|
172 if (!CryptImportPublicKeyInfo(provider, |
|
173 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, |
|
174 &context->pCertInfo->SubjectPublicKeyInfo, |
|
175 publicKey)) { |
|
176 CertFreeCertificateContext(context); |
|
177 return CryptoX_Error; |
|
178 } |
|
179 |
|
180 CertFreeCertificateContext(context); |
|
181 return CryptoX_Success; |
|
182 } |
|
183 |
|
184 /* Try to acquire context in this way: |
|
185 * 1. Enhanced provider without creating a new key set |
|
186 * 2. Enhanced provider with creating a new key set |
|
187 * 3. Default provider without creating a new key set |
|
188 * 4. Default provider without creating a new key set |
|
189 * #2 and #4 should not be needed because of the CRYPT_VERIFYCONTEXT, |
|
190 * but we add it just in case. |
|
191 * |
|
192 * @param provider Out parameter containing the provider handle. |
|
193 * @return CryptoX_Success on success, CryptoX_Error on error. |
|
194 */ |
|
195 CryptoX_Result |
|
196 CryptoAPI_InitCryptoContext(HCRYPTPROV *provider) |
|
197 { |
|
198 if (!CryptAcquireContext(provider, |
|
199 NULL, |
|
200 MS_ENHANCED_PROV, |
|
201 PROV_RSA_FULL, |
|
202 CRYPT_VERIFYCONTEXT)) { |
|
203 if (!CryptAcquireContext(provider, |
|
204 NULL, |
|
205 MS_ENHANCED_PROV, |
|
206 PROV_RSA_FULL, |
|
207 CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) { |
|
208 if (!CryptAcquireContext(provider, |
|
209 NULL, |
|
210 NULL, |
|
211 PROV_RSA_FULL, |
|
212 CRYPT_VERIFYCONTEXT)) { |
|
213 if (!CryptAcquireContext(provider, |
|
214 NULL, |
|
215 NULL, |
|
216 PROV_RSA_FULL, |
|
217 CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) { |
|
218 *provider = CryptoX_InvalidHandleValue; |
|
219 return CryptoX_Error; |
|
220 } |
|
221 } |
|
222 } |
|
223 } |
|
224 return CryptoX_Success; |
|
225 } |
|
226 |
|
227 /** |
|
228 * Begins a signature verification hash context |
|
229 * |
|
230 * @param provider The crypt provider to use |
|
231 * @param hash Out parameter for a handle to the hash context |
|
232 * @return CryptoX_Success on success, CryptoX_Error on error. |
|
233 */ |
|
234 CryptoX_Result |
|
235 CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash) |
|
236 { |
|
237 BOOL result; |
|
238 if (!provider || !hash) { |
|
239 return CryptoX_Error; |
|
240 } |
|
241 |
|
242 *hash = (HCRYPTHASH)NULL; |
|
243 result = CryptCreateHash(provider, CALG_SHA1, |
|
244 0, 0, hash); |
|
245 return result ? CryptoX_Success : CryptoX_Error; |
|
246 } |
|
247 |
|
248 /** |
|
249 * Updates a signature verification hash context |
|
250 * |
|
251 * @param hash The hash context to udpate |
|
252 * @param buf The buffer to update the hash context with |
|
253 * @param len The size of the passed in buffer |
|
254 * @return CryptoX_Success on success, CryptoX_Error on error. |
|
255 */ |
|
256 CryptoX_Result |
|
257 CryptoAPI_VerifyUpdate(HCRYPTHASH* hash, BYTE *buf, DWORD len) |
|
258 { |
|
259 BOOL result; |
|
260 if (!hash || !buf) { |
|
261 return CryptoX_Error; |
|
262 } |
|
263 |
|
264 result = CryptHashData(*hash, buf, len, 0); |
|
265 return result ? CryptoX_Success : CryptoX_Error; |
|
266 } |
|
267 |
|
268 #endif |
|
269 |
|
270 |
|
271 |