15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* ***** BEGIN LICENSE BLOCK ***** 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Version: MPL 1.1/GPL 2.0/LGPL 2.1 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The contents of this file are subject to the Mozilla Public License Version 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1.1 (the "License"); you may not use this file except in compliance with 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the License. You may obtain a copy of the License at 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * http://www.mozilla.org/MPL/ 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Software distributed under the License is distributed on an "AS IS" basis, 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * for the specific language governing rights and limitations under the 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The Original Code is the Netscape security libraries. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The Initial Developer of the Original Code is 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Netscape Communications Corporation. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Portions created by the Initial Developer are Copyright (C) 2000 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the Initial Developer. All Rights Reserved. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Contributor(s): 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Ian McGreer <mcgreer@netscape.com> 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Alternatively, the contents of this file may be used under the terms of 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * either the GNU General Public License Version 2 or later (the "GPL"), or 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in which case the provisions of the GPL or the LGPL are applicable instead 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * of those above. If you wish to allow use of your version of this file only 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * under the terms of either the GPL or the LGPL, and not to allow others to 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * use your version of this file under the terms of the MPL, indicate your 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * decision by deleting the provisions above and replace them with the notice 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * and other provisions required by the GPL or the LGPL. If you do not delete 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the provisions above, a recipient may use your version of this file under 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the terms of any one of the MPL, the GPL or the LGPL. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ***** END LICENSE BLOCK ***** */ 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pk11pub.h> 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pkcs12.h> 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <p12plcy.h> 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <secerr.h> 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h" 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/nss_util_internal.h" 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_certificate.h" 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace mozilla_security_manager { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// unicodeToItem 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For the NSS PKCS#12 library, must convert PRUnichars (shorts) to 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a buffer of octets. Must handle byte order correctly. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO: Is there a Mozilla way to do this? In the string lib? 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void unicodeToItem(const PRUnichar *uni, SECItem *item) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len = 0; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (uni[len++] != 0); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECITEM_AllocItem(NULL, item, sizeof(PRUnichar) * len); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef IS_LITTLE_ENDIAN 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i = 0; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i=0; i<len; i++) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->data[2*i ] = (unsigned char )(uni[i] << 8); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->data[2*i+1] = (unsigned char )(uni[i]); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(item->data, uni, item->len); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// write_export_data 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// write bytes to the exported PKCS#12 data buffer 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void write_export_data(void* arg, const char* buf, unsigned long len) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* dest = reinterpret_cast<std::string*>(arg); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest->append(buf, len); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// nickname_collision 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// what to do when the nickname collides with one already in the db. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Based on P12U_NicknameCollisionCallback from nss/cmd/pk12util/pk12util.c 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECItem* PR_CALLBACK 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)nickname_collision(SECItem *old_nick, PRBool *cancel, void *wincx) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *nick = NULL; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECItem *ret_nick = NULL; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERTCertificate* cert = (CERTCertificate*)wincx; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!cancel || !cert) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pk12util calls this error user cancelled? 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!old_nick) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "no nickname for cert in PKCS12 file."; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nick = CERT_MakeCANickname(cert); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nick) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if(old_nick && old_nick->data && old_nick->len && 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PORT_Strlen(nick) == old_nick->len && 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !PORT_Strncmp((char *)old_nick->data, nick, old_nick->len)) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PORT_Free(nick); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PORT_SetError(SEC_ERROR_IO); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "using nickname " << nick; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret_nick = PORT_ZNew(SECItem); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if(ret_nick == NULL) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PORT_Free(nick); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret_nick->data = (unsigned char *)nick; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret_nick->len = PORT_Strlen(nick); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret_nick; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// pip_ucs2_ascii_conversion_fn 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// required to be set by NSS (to do PKCS#12), but since we've already got 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// unicode make this a no-op. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PRBool 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pip_ucs2_ascii_conversion_fn(PRBool toUnicode, 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char *inBuf, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int inBufLen, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char *outBuf, 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int maxOutBufLen, 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int *outBufLen, 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PRBool swapBytes) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GE(maxOutBufLen, inBufLen); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // do a no-op, since I've already got Unicode. Hah! 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *outBufLen = inBufLen; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(outBuf, inBuf, inBufLen); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PR_TRUE; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Based on nsPKCS12Blob::ImportFromFileHelper. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)nsPKCS12Blob_ImportHelper(const char* pkcs12_data, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t pkcs12_len, 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::string16& password, 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_extractable, 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool try_zero_length_secitem, 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PK11SlotInfo *slot, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::CertificateList* imported_certs) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(pkcs12_data); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(slot); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int import_result = net::ERR_PKCS12_IMPORT_FAILED; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECStatus srv = SECSuccess; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12DecoderContext *dcx = NULL; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECItem unicodePw; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECItem attribute_value; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CK_BBOOL attribute_data = CK_FALSE; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SEC_PKCS12DecoderItem* decoder_item = NULL; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unicodePw.type = siBuffer; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unicodePw.len = 0; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unicodePw.data = NULL; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!try_zero_length_secitem) { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unicodeToItem(password.c_str(), &unicodePw); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize the decoder 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dcx = SEC_PKCS12DecoderStart(&unicodePw, slot, 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // wincx 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // dOpen, dClose, dRead, dWrite, dArg: NULL 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specifies default impl using memory buffer. 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, NULL, NULL, NULL, NULL); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!dcx) { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SECFailure; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto finish; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // feed input to the decoder 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SEC_PKCS12DecoderUpdate(dcx, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (unsigned char*)pkcs12_data, 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pkcs12_len); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) goto finish; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // verify the blob 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SEC_PKCS12DecoderVerify(dcx); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) goto finish; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // validate bags 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) goto finish; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // import certificate and key 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SEC_PKCS12DecoderImportBags(dcx); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) goto finish; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attribute_value.data = &attribute_data; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attribute_value.len = sizeof(attribute_data); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SEC_PKCS12DecoderIterateInit(dcx); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) goto finish; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (imported_certs) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) imported_certs->clear(); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Collect the list of decoded certificates, and mark private keys 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // non-extractable if needed. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (SEC_PKCS12DecoderIterateNext(dcx, &decoder_item) == SECSuccess) { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (decoder_item->type != SEC_OID_PKCS12_V1_CERT_BAG_ID) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERTCertificate* cert = PK11_FindCertFromDERCertItem( 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) slot, decoder_item->der, 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); // wincx 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!cert) { 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Could not grab a handle to the certificate in the slot " 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "from the corresponding PKCS#12 DER certificate."; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add the cert to the list 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (imported_certs) { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Empty list of intermediates. 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::X509Certificate::OSCertHandles intermediates; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) imported_certs->push_back( 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::X509Certificate::CreateFromHandle(cert, intermediates)); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Once we have determined that the imported certificate has an 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // associated private key too, only then can we mark the key as 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // non-extractable. 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!decoder_item->hasKey) { 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_DestroyCertificate(cert); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate through all the imported PKCS12 items and mark any accompanying 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // private keys as non-extractable. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_extractable) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECKEYPrivateKey* privKey = PK11_FindPrivateKeyFromCert(slot, cert, 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); // wincx 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (privKey) { 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark the private key as non-extractable. 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = PK11_WriteRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &attribute_value); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECKEY_DestroyPrivateKey(privKey); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Could not set CKA_EXTRACTABLE attribute on private " 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "key."; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_DestroyCertificate(cert); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_DestroyCertificate(cert); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) goto finish; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import_result = net::OK; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)finish: 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If srv != SECSuccess, NSS probably set a specific error code. 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should use that error code instead of inventing a new one 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for every error possible. 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv != SECSuccess) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int error = PORT_GetError(); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "PKCS#12 import failed with error " << error; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (error) { 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SEC_ERROR_BAD_PASSWORD: 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT: 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import_result = net::ERR_PKCS12_IMPORT_BAD_PASSWORD; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SEC_ERROR_PKCS12_INVALID_MAC: 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import_result = net::ERR_PKCS12_IMPORT_INVALID_MAC; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SEC_ERROR_BAD_DER: 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SEC_ERROR_PKCS12_DECODING_PFX: 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE: 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import_result = net::ERR_PKCS12_IMPORT_INVALID_FILE; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM: 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE: 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM: 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SEC_ERROR_PKCS12_UNSUPPORTED_VERSION: 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import_result = net::ERR_PKCS12_IMPORT_UNSUPPORTED; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import_result = net::ERR_PKCS12_IMPORT_FAILED; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Finish the decoder 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dcx) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12DecoderFinish(dcx); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECITEM_ZfreeItem(&unicodePw, PR_FALSE); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return import_result; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Attempt to read the CKA_EXTRACTABLE attribute on a private key inside 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a token. On success, store the attribute in |extractable| and return 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SECSuccess. 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)isExtractable(SECKEYPrivateKey *privKey, PRBool *extractable) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECItem value; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECStatus rv; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv=PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE, &value); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != SECSuccess) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((value.len == 1) && (value.data != NULL)) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *extractable = !!(*(CK_BBOOL*)value.data); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = SECFailure; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECITEM_FreeItem(&value, PR_FALSE); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PKCS12InitSingleton { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // From the PKCS#12 section of nsNSSComponent::InitializeNSS in 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // nsNSSComponent.cpp. 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PKCS12InitSingleton() { 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Enable ciphers for PKCS#12 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12EnableCipher(PKCS12_DES_56, 1); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set no-op ascii-ucs2 conversion function to work around weird NSS 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // interface. Thankfully, PKCS12 appears to be the only thing in NSS that 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // uses PORT_UCS2_ASCIIConversion, so this doesn't break anything else. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PORT_SetUCS2_ASCIIConversionFunction(pip_ucs2_ascii_conversion_fn); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Leaky so it can be initialized on worker threads and because there is no 3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// cleanup necessary. 3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static base::LazyInstance<PKCS12InitSingleton>::Leaky g_pkcs12_init_singleton = 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LAZY_INSTANCE_INITIALIZER; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnsurePKCS12Init() { 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_pkcs12_init_singleton.Get(); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Based on nsPKCS12Blob::ImportFromFile. 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int nsPKCS12Blob_Import(PK11SlotInfo* slot, 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* pkcs12_data, 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t pkcs12_len, 358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::string16& password, 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_extractable, 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::CertificateList* imported_certs) { 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password, 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_extractable, false, slot, 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) imported_certs); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When the user entered a zero length password: 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // An empty password should be represented as an empty 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // string (a SECItem that contains a single terminating 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NULL UTF16 character), but some applications use a 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // zero length SECItem. 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We try both variations, zero length item and empty string, 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // without giving a user prompt when trying the different empty password 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // flavors. 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv == net::ERR_PKCS12_IMPORT_BAD_PASSWORD && password.empty()) { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password, 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_extractable, true, slot, imported_certs); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Based on nsPKCS12Blob::ExportToFile 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Having already loaded the certs, form them into a blob (loading the keys 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// also), encode the blob, and stuff it into the file. 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO: handle slots correctly 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mirror "slotToUse" behavior from PSM 1.x 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// verify the cert array to start off with? 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// set appropriate error codes 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)nsPKCS12Blob_Export(std::string* output, 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::CertificateList& certs, 393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::string16& password) 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int return_count = 0; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECStatus srv = SECSuccess; 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12ExportContext *ecx = NULL; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12SafeInfo *certSafe = NULL, *keySafe = NULL; 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECItem unicodePw; 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unicodePw.type = siBuffer; 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unicodePw.len = 0; 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unicodePw.data = NULL; 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int numCertsExported = 0; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // get file password (unicode) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unicodeToItem(password.c_str(), &unicodePw); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // what about slotToUse in psm 1.x ??? 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // create export context 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ecx = SEC_PKCS12CreateExportContext(NULL, NULL, NULL /*slot*/, NULL); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ecx) { 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SECFailure; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto finish; 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // add password integrity 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SEC_PKCS12AddPasswordIntegrity(ecx, &unicodePw, SEC_OID_SHA1); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) goto finish; 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i=0; i<certs.size(); i++) { 421eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(certs[i].get()); 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERTCertificate* nssCert = certs[i]->os_cert_handle(); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(nssCert); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We only allow certificate and private key extraction if the corresponding 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CKA_EXTRACTABLE private key attribute is set to CK_TRUE. Most hardware 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tokens including smartcards enforce this behavior. An internal (soft) 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // token may ignore this attribute (and hence still be able to export) but 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we still refuse to attempt an export. 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In addition, some tokens may not support this attribute, in which case 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we still attempt the export and let the token implementation dictate 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the export behavior. 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (nssCert->slot) { 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECKEYPrivateKey *privKey=PK11_FindKeyByDERCert(nssCert->slot, 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nssCert, 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); // wincx 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (privKey) { 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PRBool privKeyIsExtractable = PR_FALSE; 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECStatus rv = isExtractable(privKey, &privKeyIsExtractable); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECKEY_DestroyPrivateKey(privKey); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv == SECSuccess && !privKeyIsExtractable) { 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Private key is not extractable"; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // XXX this is why, to verify the slot is the same 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // PK11_FindObjectForCert(nssCert, NULL, slot); 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // create the cert and key safes 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keySafe = SEC_PKCS12CreateUnencryptedSafe(ecx); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!SEC_PKCS12IsEncryptionAllowed() || PK11_IsFIPS()) { 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) certSafe = keySafe; 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) certSafe = SEC_PKCS12CreatePasswordPrivSafe(ecx, &unicodePw, 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!certSafe || !keySafe) { 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "!certSafe || !keySafe " << certSafe << " " << keySafe; 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SECFailure; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto finish; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // add the cert and key to the blob 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SEC_PKCS12AddCertAndKey(ecx, certSafe, NULL, nssCert, 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_GetDefaultCertDB(), 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keySafe, NULL, PR_TRUE, &unicodePw, 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) goto finish; 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++numCertsExported; 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!numCertsExported) goto finish; 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // encode and write 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srv = SEC_PKCS12Encode(ecx, write_export_data, output); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) goto finish; 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_count = numCertsExported; 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)finish: 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (srv) 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "PKCS#12 export failed with error " << PORT_GetError(); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ecx) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SEC_PKCS12DestroyExportContext(ecx); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECITEM_ZfreeItem(&unicodePw, PR_FALSE); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return return_count; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace mozilla_security_manager 489