OLD | NEW |
---|---|
1 /* ***** BEGIN LICENSE BLOCK ***** | 1 /* ***** BEGIN LICENSE BLOCK ***** |
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
3 * | 3 * |
4 * The contents of this file are subject to the Mozilla Public License Version | 4 * The contents of this file are subject to the Mozilla Public License Version |
5 * 1.1 (the "License"); you may not use this file except in compliance with | 5 * 1.1 (the "License"); you may not use this file except in compliance with |
6 * the License. You may obtain a copy of the License at | 6 * the License. You may obtain a copy of the License at |
7 * http://www.mozilla.org/MPL/ | 7 * http://www.mozilla.org/MPL/ |
8 * | 8 * |
9 * Software distributed under the License is distributed on an "AS IS" basis, | 9 * Software distributed under the License is distributed on an "AS IS" basis, |
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | 10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
50 #include "net/base/x509_certificate.h" | 50 #include "net/base/x509_certificate.h" |
51 | 51 |
52 namespace mozilla_security_manager { | 52 namespace mozilla_security_manager { |
53 | 53 |
54 namespace { | 54 namespace { |
55 | 55 |
56 // unicodeToItem | 56 // unicodeToItem |
57 // | 57 // |
58 // For the NSS PKCS#12 library, must convert PRUnichars (shorts) to | 58 // For the NSS PKCS#12 library, must convert PRUnichars (shorts) to |
59 // a buffer of octets. Must handle byte order correctly. | 59 // a buffer of octets. Must handle byte order correctly. |
60 // TODO: Is there a mozilla way to do this? In the string lib? | 60 // TODO: Is there a Mozilla way to do this? In the string lib? |
61 void unicodeToItem(const PRUnichar *uni, SECItem *item) | 61 void unicodeToItem(const PRUnichar *uni, SECItem *item) |
62 { | 62 { |
63 int len = 0; | 63 int len = 0; |
64 while (uni[len++] != 0); | 64 while (uni[len++] != 0); |
65 SECITEM_AllocItem(NULL, item, sizeof(PRUnichar) * len); | 65 SECITEM_AllocItem(NULL, item, sizeof(PRUnichar) * len); |
66 #ifdef IS_LITTLE_ENDIAN | 66 #ifdef IS_LITTLE_ENDIAN |
67 int i = 0; | 67 int i = 0; |
68 for (i=0; i<len; i++) { | 68 for (i=0; i<len; i++) { |
69 item->data[2*i ] = (unsigned char )(uni[i] << 8); | 69 item->data[2*i ] = (unsigned char )(uni[i] << 8); |
70 item->data[2*i+1] = (unsigned char )(uni[i]); | 70 item->data[2*i+1] = (unsigned char )(uni[i]); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
131 PRBool | 131 PRBool |
132 pip_ucs2_ascii_conversion_fn(PRBool toUnicode, | 132 pip_ucs2_ascii_conversion_fn(PRBool toUnicode, |
133 unsigned char *inBuf, | 133 unsigned char *inBuf, |
134 unsigned int inBufLen, | 134 unsigned int inBufLen, |
135 unsigned char *outBuf, | 135 unsigned char *outBuf, |
136 unsigned int maxOutBufLen, | 136 unsigned int maxOutBufLen, |
137 unsigned int *outBufLen, | 137 unsigned int *outBufLen, |
138 PRBool swapBytes) | 138 PRBool swapBytes) |
139 { | 139 { |
140 CHECK_GE(maxOutBufLen, inBufLen); | 140 CHECK_GE(maxOutBufLen, inBufLen); |
141 // do a no-op, since I've already got unicode. Hah! | 141 // do a no-op, since I've already got Unicode. Hah! |
142 *outBufLen = inBufLen; | 142 *outBufLen = inBufLen; |
143 memcpy(outBuf, inBuf, inBufLen); | 143 memcpy(outBuf, inBuf, inBufLen); |
144 return PR_TRUE; | 144 return PR_TRUE; |
145 } | 145 } |
146 | 146 |
147 // Based on nsPKCS12Blob::ImportFromFileHelper. | 147 // Based on nsPKCS12Blob::ImportFromFileHelper. |
148 int | 148 int |
149 nsPKCS12Blob_ImportHelper(const char* pkcs12_data, | 149 nsPKCS12Blob_ImportHelper(const char* pkcs12_data, |
150 size_t pkcs12_len, | 150 size_t pkcs12_len, |
151 const string16& password, | 151 const string16& password, |
152 bool is_extractable, | 152 bool is_extractable, |
153 bool try_zero_length_secitem, | 153 bool try_zero_length_secitem, |
154 PK11SlotInfo *slot) | 154 PK11SlotInfo *slot, |
155 net::CertificateList* imported_certs) | |
155 { | 156 { |
156 DCHECK(pkcs12_data); | 157 DCHECK(pkcs12_data); |
157 DCHECK(slot); | 158 DCHECK(slot); |
158 int import_result = net::ERR_PKCS12_IMPORT_FAILED; | 159 int import_result = net::ERR_PKCS12_IMPORT_FAILED; |
159 SECStatus srv = SECSuccess; | 160 SECStatus srv = SECSuccess; |
160 SEC_PKCS12DecoderContext *dcx = NULL; | 161 SEC_PKCS12DecoderContext *dcx = NULL; |
161 SECItem unicodePw; | 162 SECItem unicodePw; |
163 SECItem attribute_value; | |
164 CK_BBOOL attribute_data = CK_FALSE; | |
165 const SEC_PKCS12DecoderItem* decoder_item = NULL; | |
166 | |
162 unicodePw.type = siBuffer; | 167 unicodePw.type = siBuffer; |
163 unicodePw.len = 0; | 168 unicodePw.len = 0; |
164 unicodePw.data = NULL; | 169 unicodePw.data = NULL; |
165 if (!try_zero_length_secitem) { | 170 if (!try_zero_length_secitem) { |
166 unicodeToItem(password.c_str(), &unicodePw); | 171 unicodeToItem(password.c_str(), &unicodePw); |
167 } | 172 } |
168 | 173 |
169 // Initialize the decoder | 174 // Initialize the decoder |
170 dcx = SEC_PKCS12DecoderStart(&unicodePw, slot, | 175 dcx = SEC_PKCS12DecoderStart(&unicodePw, slot, |
171 // wincx | 176 // wincx |
172 NULL, | 177 NULL, |
173 // dOpen, dClose, dRead, dWrite, dArg: NULL | 178 // dOpen, dClose, dRead, dWrite, dArg: NULL |
174 // specifies default impl using memory buffer. | 179 // specifies default impl using memory buffer. |
175 NULL, NULL, NULL, NULL, NULL); | 180 NULL, NULL, NULL, NULL, NULL); |
176 if (!dcx) { | 181 if (!dcx) { |
177 srv = SECFailure; | 182 srv = SECFailure; |
178 goto finish; | 183 goto finish; |
179 } | 184 } |
180 // feed input to the decoder | 185 // feed input to the decoder |
181 srv = SEC_PKCS12DecoderUpdate(dcx, | 186 srv = SEC_PKCS12DecoderUpdate(dcx, |
182 (unsigned char*)pkcs12_data, | 187 (unsigned char*)pkcs12_data, |
183 pkcs12_len); | 188 pkcs12_len); |
184 if (srv) goto finish; | 189 if (srv) goto finish; |
185 // verify the blob | 190 // verify the blob |
186 srv = SEC_PKCS12DecoderVerify(dcx); | 191 srv = SEC_PKCS12DecoderVerify(dcx); |
187 if (srv) goto finish; | 192 if (srv) goto finish; |
188 // validate bags | 193 // validate bags |
189 srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision); | 194 srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision); |
190 if (srv) goto finish; | 195 if (srv) goto finish; |
191 // import cert and key | 196 // import certificate and key |
192 srv = SEC_PKCS12DecoderImportBags(dcx); | 197 srv = SEC_PKCS12DecoderImportBags(dcx); |
193 if (srv) goto finish; | 198 if (srv) goto finish; |
194 | 199 |
195 if (!is_extractable) { | 200 attribute_value.data = &attribute_data; |
196 SECItem attribute_value; | 201 attribute_value.len = sizeof(attribute_data); |
197 CK_BBOOL attribute_data = CK_FALSE; | |
198 attribute_value.data = &attribute_data; | |
199 attribute_value.len = sizeof(attribute_data); | |
200 | 202 |
201 srv = SEC_PKCS12DecoderIterateInit(dcx); | 203 srv = SEC_PKCS12DecoderIterateInit(dcx); |
202 if (srv) goto finish; | 204 if (srv) goto finish; |
203 | 205 |
204 const SEC_PKCS12DecoderItem* decoder_item = NULL; | 206 if (imported_certs) |
207 imported_certs->clear(); | |
208 | |
209 // Collect the list of decoded certificates, and mark private keys | |
210 // non-extractable if needed. | |
211 while (SEC_PKCS12DecoderIterateNext(dcx, &decoder_item) == SECSuccess) { | |
212 if (decoder_item->type != SEC_OID_PKCS12_V1_CERT_BAG_ID) | |
213 continue; | |
214 | |
215 CERTCertificate* cert = PK11_FindCertFromDERCertItem( | |
216 slot, decoder_item->der, | |
217 NULL); // wincx | |
218 if (!cert) { | |
219 LOG(ERROR) << "Could not grab a handle to the certificate in the slot " | |
220 << "from the corresponding PKCS#12 DER certificate."; | |
221 continue; | |
222 } | |
223 | |
224 // Add the cert to the list | |
225 if (imported_certs) { | |
226 // Empty list of intermediates. | |
227 net::X509Certificate::OSCertHandles intermediates; | |
228 imported_certs->push_back( | |
229 net::X509Certificate::CreateFromHandle(cert, intermediates)); | |
230 } | |
231 | |
232 // Once we have determined that the imported certificate has an | |
233 // associated private key too, only then can we mark the key as | |
234 // non-extractable. | |
235 if (!decoder_item->hasKey) | |
236 continue; | |
wtc
2011/12/08 00:07:43
BUG: we also need to call
CERT_DestroyCertificat
Greg Spencer (Chromium)
2011/12/09 18:51:38
Done.
| |
237 | |
205 // Iterate through all the imported PKCS12 items and mark any accompanying | 238 // Iterate through all the imported PKCS12 items and mark any accompanying |
206 // private keys as unextractable. | 239 // private keys as non-extractable. |
207 while (SEC_PKCS12DecoderIterateNext(dcx, &decoder_item) == SECSuccess) { | 240 if (!is_extractable) { |
208 if (decoder_item->type != SEC_OID_PKCS12_V1_CERT_BAG_ID) | |
209 continue; | |
210 if (!decoder_item->hasKey) | |
211 continue; | |
212 | |
213 // Once we have determined that the imported certificate has an | |
214 // associated private key too, only then can we mark the key as | |
215 // unextractable. | |
216 CERTCertificate* cert = PK11_FindCertFromDERCertItem( | |
217 slot, decoder_item->der, | |
218 NULL); // wincx | |
219 if (!cert) { | |
220 LOG(ERROR) << "Could not grab a handle to the certificate in the slot " | |
221 << "from the corresponding PKCS#12 DER certificate."; | |
222 continue; | |
223 } | |
224 SECKEYPrivateKey* privKey = PK11_FindPrivateKeyFromCert(slot, cert, | 241 SECKEYPrivateKey* privKey = PK11_FindPrivateKeyFromCert(slot, cert, |
225 NULL); // wincx | 242 NULL); // wincx |
226 CERT_DestroyCertificate(cert); | |
227 if (privKey) { | 243 if (privKey) { |
228 // Mark the private key as unextractable. | 244 // Mark the private key as non-extractable. |
229 srv = PK11_WriteRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE, | 245 srv = PK11_WriteRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE, |
230 &attribute_value); | 246 &attribute_value); |
231 SECKEY_DestroyPrivateKey(privKey); | 247 SECKEY_DestroyPrivateKey(privKey); |
232 if (srv) { | 248 if (srv) { |
233 LOG(ERROR) << "Could not set CKA_EXTRACTABLE attribute on private " | 249 LOG(ERROR) << "Could not set CKA_EXTRACTABLE attribute on private " |
234 << "key."; | 250 << "key."; |
251 CERT_DestroyCertificate(cert); | |
235 break; | 252 break; |
236 } | 253 } |
237 } | 254 } |
238 } | 255 } |
256 CERT_DestroyCertificate(cert); | |
239 if (srv) goto finish; | 257 if (srv) goto finish; |
240 } | 258 } |
241 | |
242 import_result = net::OK; | 259 import_result = net::OK; |
243 finish: | 260 finish: |
244 // If srv != SECSuccess, NSS probably set a specific error code. | 261 // If srv != SECSuccess, NSS probably set a specific error code. |
245 // We should use that error code instead of inventing a new one | 262 // We should use that error code instead of inventing a new one |
246 // for every error possible. | 263 // for every error possible. |
247 if (srv != SECSuccess) { | 264 if (srv != SECSuccess) { |
248 int error = PORT_GetError(); | 265 int error = PORT_GetError(); |
249 LOG(ERROR) << "PKCS#12 import failed with error " << error; | 266 LOG(ERROR) << "PKCS#12 import failed with error " << error; |
250 switch (error) { | 267 switch (error) { |
251 case SEC_ERROR_BAD_PASSWORD: | 268 case SEC_ERROR_BAD_PASSWORD: |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
328 | 345 |
329 void EnsurePKCS12Init() { | 346 void EnsurePKCS12Init() { |
330 g_pkcs12_init_singleton.Get(); | 347 g_pkcs12_init_singleton.Get(); |
331 } | 348 } |
332 | 349 |
333 // Based on nsPKCS12Blob::ImportFromFile. | 350 // Based on nsPKCS12Blob::ImportFromFile. |
334 int nsPKCS12Blob_Import(PK11SlotInfo* slot, | 351 int nsPKCS12Blob_Import(PK11SlotInfo* slot, |
335 const char* pkcs12_data, | 352 const char* pkcs12_data, |
336 size_t pkcs12_len, | 353 size_t pkcs12_len, |
337 const string16& password, | 354 const string16& password, |
338 bool is_extractable) { | 355 bool is_extractable, |
356 net::CertificateList* imported_certs) { | |
339 | 357 |
340 int rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password, | 358 int rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password, |
341 is_extractable, false, slot); | 359 is_extractable, false, slot, |
360 imported_certs); | |
342 | 361 |
343 // When the user entered a zero length password: | 362 // When the user entered a zero length password: |
344 // An empty password should be represented as an empty | 363 // An empty password should be represented as an empty |
345 // string (a SECItem that contains a single terminating | 364 // string (a SECItem that contains a single terminating |
346 // NULL UTF16 character), but some applications use a | 365 // NULL UTF16 character), but some applications use a |
347 // zero length SECItem. | 366 // zero length SECItem. |
348 // We try both variations, zero length item and empty string, | 367 // We try both variations, zero length item and empty string, |
349 // without giving a user prompt when trying the different empty password | 368 // without giving a user prompt when trying the different empty password |
350 // flavors. | 369 // flavors. |
351 if (rv == net::ERR_PKCS12_IMPORT_BAD_PASSWORD && password.empty()) { | 370 if (rv == net::ERR_PKCS12_IMPORT_BAD_PASSWORD && password.empty()) { |
352 rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password, | 371 rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password, |
353 is_extractable, true, slot); | 372 is_extractable, true, slot, imported_certs); |
354 } | 373 } |
355 return rv; | 374 return rv; |
356 } | 375 } |
357 | 376 |
358 // Based on nsPKCS12Blob::ExportToFile | 377 // Based on nsPKCS12Blob::ExportToFile |
359 // | 378 // |
360 // Having already loaded the certs, form them into a blob (loading the keys | 379 // Having already loaded the certs, form them into a blob (loading the keys |
361 // also), encode the blob, and stuff it into the file. | 380 // also), encode the blob, and stuff it into the file. |
362 // | 381 // |
363 // TODO: handle slots correctly | 382 // TODO: handle slots correctly |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
456 finish: | 475 finish: |
457 if (srv) | 476 if (srv) |
458 LOG(ERROR) << "PKCS#12 export failed with error " << PORT_GetError(); | 477 LOG(ERROR) << "PKCS#12 export failed with error " << PORT_GetError(); |
459 if (ecx) | 478 if (ecx) |
460 SEC_PKCS12DestroyExportContext(ecx); | 479 SEC_PKCS12DestroyExportContext(ecx); |
461 SECITEM_ZfreeItem(&unicodePw, PR_FALSE); | 480 SECITEM_ZfreeItem(&unicodePw, PR_FALSE); |
462 return return_count; | 481 return return_count; |
463 } | 482 } |
464 | 483 |
465 } // namespace mozilla_security_manager | 484 } // namespace mozilla_security_manager |
OLD | NEW |