Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
5 #ifdef XP_WIN
6 #ifndef WIN32_LEAN_AND_MEAN
7 #define WIN32_LEAN_AND_MEAN
8 #endif
9 #endif
11 #include <stdlib.h>
12 #include "cryptox.h"
14 #if defined(MAR_NSS)
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 }
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 }
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 }
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 }
64 *ctx = VFY_CreateContext(*publicKey, NULL,
65 SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL);
66 if (*ctx == NULL) {
67 return CryptoX_Error;
68 }
70 status = VFY_Begin(*ctx);
71 return SECSuccess == status ? CryptoX_Success : CryptoX_Error;
72 }
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 }
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 }
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 }
126 signatureReversed = malloc(signatureLen);
127 if (!signatureReversed) {
128 return CryptoX_Error;
129 }
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 }
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 }
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 }
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 }
180 CertFreeCertificateContext(context);
181 return CryptoX_Success;
182 }
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 }
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 }
242 *hash = (HCRYPTHASH)NULL;
243 result = CryptCreateHash(provider, CALG_SHA1,
244 0, 0, hash);
245 return result ? CryptoX_Success : CryptoX_Error;
246 }
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 }
264 result = CryptHashData(*hash, buf, len, 0);
265 return result ? CryptoX_Success : CryptoX_Error;
266 }
268 #endif