📄 p12res.c
字号:
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "p12res.h"#include "minihttp.h"#include "pk11func.h"#include "secmod.h"#include "p12.h"#include "p12plcy.h"#include "secerr.h"#include "newproto.h"#include "messages.h"#include "advisor.h"#define SSMRESOURCE(object) (&object->super)#define PKCS12_IN_BUFFER_SIZE 2048static SSMStatusssmpkcs12context_createpkcs12file(SSMPKCS12Context *cx, PRBool forceAuthenticate, CERTCertificate **certArr, PRIntn numCerts);SECStatusSSM_UnicodeConversion(SECItem *dest, SECItem *src, PRBool toUnicode, PRBool swapBytes){ unsigned int allocLen; if(!dest || !src) { return SECFailure; } allocLen = ((toUnicode) ? (src->len << 2) : src->len); if (allocLen == 0) { /* empty string: we need to pad it by 2 bytes */ allocLen = 2; } dest->data = SSM_ZNEW_ARRAY(unsigned char, allocLen); if(!SSM_UCS2_ASCIIConversion(toUnicode, src->data, src->len, dest->data, allocLen, &dest->len, swapBytes)) { PR_Free(dest->data); dest->data = NULL; return SECFailure; } return SECSuccess;}SSMStatusSSMPKCS12Context_Create(void *arg, SSMControlConnection *ctrl, SSMResource **res){ SSMPKCS12Context *cxt = NULL; SSMPKCS12CreateArg *createArg = (SSMPKCS12CreateArg*)arg; SSMStatus rv; cxt = SSM_ZNEW(SSMPKCS12Context); if (cxt == NULL) { return SSM_ERR_OUT_OF_MEMORY; } rv = SSMPKCS12Context_Init(ctrl,cxt,SSM_RESTYPE_PKCS12_CONTEXT , createArg->isExportContext); if (rv != PR_SUCCESS) { goto loser; } *res = SSMRESOURCE(cxt); return PR_SUCCESS; loser: if (cxt != NULL) { SSM_FreeResource(SSMRESOURCE(cxt)); } *res = NULL; return rv;}SSMStatusSSMPKCS12Context_Init(SSMControlConnection *ctrl, SSMPKCS12Context *res, SSMResourceType type, PRBool isExportContext){ res->m_isExportContext = isExportContext; res->m_password = NULL; res->m_inputProcessed = PR_FALSE; res->m_file = NULL; res->m_digestFile = NULL; res->m_error = PR_FALSE; return SSMResource_Init(ctrl, SSMRESOURCE(res), type);}SSMStatusSSMPKCS12Context_Destroy(SSMResource *res, PRBool doFree) { SSMPKCS12Context *cxt = (SSMPKCS12Context*)res; SSMResource_Destroy(res, PR_FALSE); if (cxt->m_password != NULL) { PR_Free(cxt->m_password); cxt->m_password = NULL; } if (cxt->m_cert != NULL) { CERT_DestroyCertificate(cxt->m_cert); cxt->m_cert = NULL; } if (doFree) { PR_Free(res); } return PR_SUCCESS;}static SSMStatusSSMPKCS12Context_HandlePasswordRequest(SSMResource *res, HTTPRequest *req) { char *password, *confirmPassword; SSMPKCS12Context *p12Cxt = (SSMPKCS12Context*)res; SSMStatus rv = SSM_FAILURE; /* Let's get the password out of the dialog. */ if (res->m_buttonType != SSM_BUTTON_OK) { goto loser; } rv = SSM_HTTPParamValue(req, "passwd", &password); if (rv != SSM_SUCCESS) { goto loser; } rv = SSM_HTTPParamValue(req, "confirmPasswd", &confirmPassword); if (rv != SSM_SUCCESS) { goto loser; } if (strcmp(password, confirmPassword) != 0) { /* Should re-prompt, but for now we fail. */ rv = SSM_FAILURE; goto loser; } p12Cxt->m_password = PL_strdup(password); goto done; loser: p12Cxt->m_password = NULL; done: SSM_LockResource(res); SSM_NotifyResource(res); SSM_UnlockResource(res); SSM_HTTPDefaultCommandHandler(req); p12Cxt->m_inputProcessed = PR_TRUE; return rv;}SSMStatusSSMPKCS12Context_FormSubmitHandler(SSMResource *res, HTTPRequest *req){ char *formName; SSMStatus rv=SSM_FAILURE; rv = SSM_HTTPParamValue(req, "formName", &formName); if (rv != SSM_SUCCESS) { goto loser; } if (!strcmp(formName, "cert_backup_form")) { rv = SSMPKCS12Context_HandlePasswordRequest(res, req); } else if (!strcmp(formName, "set_db_password")) { rv = SSM_SetDBPasswordHandler(req); } else { goto loser; } return rv; loser: SSM_HTTPDefaultCommandHandler(req); return SSM_FAILURE;}static voidssmpkcs12context_writetoexportfile(void *arg, const char *buf, unsigned long len){ SSMPKCS12Context *p12Cxt = (SSMPKCS12Context*)arg; PRInt32 bytesWritten; if (p12Cxt == NULL) { return; } if (p12Cxt->m_file == NULL) { p12Cxt->m_error = PR_TRUE; return; } bytesWritten = PR_Write(p12Cxt->m_file, buf, len); if (bytesWritten != len) { p12Cxt->m_error = PR_TRUE; }}SSMStatusSSMPKCS12Context_CreatePKCS12FileForMultipleCerts(SSMPKCS12Context *p12Cxt, PRBool forceAuthenticate, CERTCertificate **certArr, PRIntn numCerts){ return ssmpkcs12context_createpkcs12file(p12Cxt, forceAuthenticate, certArr, numCerts);}SSMStatusSSMPKCS12Context_CreatePKCS12File(SSMPKCS12Context *cxt, PRBool forceAuthenticate){ return ssmpkcs12context_createpkcs12file(cxt, forceAuthenticate, &cxt->m_cert, 1);}static SSMStatusssmpkcs12context_createpkcs12file(SSMPKCS12Context *cxt, PRBool forceAuthenticate, CERTCertificate **certArr, PRIntn numCerts){ SEC_PKCS12ExportContext *p12ecx = NULL; SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL; SECItem pwitem = { siBuffer, NULL, 0 }; PK11SlotInfo *slot = NULL; PK11SlotInfo *slotToUse = NULL; SSMControlConnection *ctrl; SSMStatus rv=SSM_FAILURE; int i; if (cxt == NULL || certArr == NULL || numCerts == 0) { return SSM_ERR_BAD_REQUEST; } /* * We're about to send the UI event requesting the password to use * when encrypting */ SSM_LockResource(&cxt->super); cxt->m_inputProcessed = PR_FALSE; rv = SSMControlConnection_SendUIEvent(SSMRESOURCE(cxt)->m_connection, "get", "cert_backup", SSMRESOURCE(cxt), (numCerts > 1) ? "multipleCerts=1" : NULL, &SSMRESOURCE(cxt)->m_clientContext); if (rv != SSM_SUCCESS) { SSM_UnlockResource(SSMRESOURCE(cxt)); goto loser; } /* * Wait until the form is submitted to proceed. We'll get notified. */ SSM_WaitResource(SSMRESOURCE(cxt), PR_INTERVAL_NO_TIMEOUT); SSM_UnlockResource(SSMRESOURCE(cxt)); if (cxt->m_password == NULL || cxt->super.m_buttonType == SSM_BUTTON_CANCEL) { rv = SSM_ERR_NO_PASSWORD; goto loser; } /* Wait for the dialog box to go down so that when it disappears, * the window doesn't take away the password prompt. */ PR_Sleep(PR_TicksPerSecond()); ctrl = SSMRESOURCE(cxt)->m_connection; pwitem.data = (unsigned char *) cxt->m_password; pwitem.len = strlen(cxt->m_password); PK11_FindObjectForCert(certArr[0], ctrl, &slot); if (slot == NULL) { rv = SSM_FAILURE; goto loser; } slotToUse = slot; if (forceAuthenticate) { PK11_Logout(slot); } if (PK11_Authenticate(slot, PR_TRUE, ctrl) != SECSuccess) { rv = SSM_ERR_BAD_DB_PASSWORD; goto loser; } p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, slot, ctrl); if (p12ecx == NULL) { rv = SSM_FAILURE; goto loser; } if (SEC_PKCS12AddPasswordIntegrity(p12ecx, &pwitem, SEC_OID_SHA1) != SECSuccess) { rv = SSM_ERR_BAD_PASSWORD; goto loser; } for (i=0; i <numCerts; i++) { PK11_FindObjectForCert(certArr[i], ctrl, &slot); if (slot != slotToUse) { continue; } keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx); if (!SEC_PKCS12IsEncryptionAllowed() || PK11_IsFIPS()) { certSafe = keySafe; } else { certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, &pwitem, SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC); } if (certSafe == NULL || keySafe == NULL) { rv = SSM_FAILURE; goto loser; } if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, certArr[i], SSMRESOURCE(cxt)->m_connection->m_certdb, keySafe, NULL, PR_TRUE, &pwitem, SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC) != SECSuccess) { rv = SSM_FAILURE; goto loser; } } /* Done with the password, free it */ PR_Free(cxt->m_password); cxt->m_password = NULL; rv = SSM_RequestFilePathFromUser(SSMRESOURCE(cxt), "pkcs12_export_file_prompt", "*.p12", PR_FALSE); if (rv != SSM_SUCCESS || cxt->super.m_fileName == NULL) { rv = SSM_ERR_BAD_FILENAME; goto loser; } cxt->m_file = PR_Open (cxt->super.m_fileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600); if (cxt->m_file == NULL) { rv = SSM_ERR_BAD_FILENAME; goto loser; } if (SEC_PKCS12Encode(p12ecx, ssmpkcs12context_writetoexportfile, cxt) != SECSuccess) { rv = SSM_FAILURE; goto loser; } PR_Close(cxt->m_file); if (slotToUse) { PK11_FreeSlot(slotToUse); } SEC_PKCS12DestroyExportContext(p12ecx); return SSM_SUCCESS; loser: if (p12ecx != NULL) { SEC_PKCS12DestroyExportContext(p12ecx); } if (slot && cxt->m_cert && (slot != cxt->m_cert->slot)) { PK11_FreeSlot(slot); } PR_FREEIF(cxt->m_password); cxt->m_password = NULL; return rv;}/* This function converts ASCII strings to UCS2 strings in Network Byte Order.** The "swapBytes" argument is ignored. ** The PKCS#12 code only makes it true on Little Endian systems, ** where it was intended to force the output into NBO.*/PRBool SSM_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf, unsigned int inBufLen, unsigned char *outBuf, unsigned int maxOutBufLen, unsigned int *outBufLen, PRBool swapBytes){ if (!inBuf || !outBuf || !outBufLen) { return PR_FALSE; } if (toUnicode) { PRBool rv;#ifdef DEBUG unsigned int outLen; int i; fprintf(stderr,"\n---ssm_ConvertAsciiToUCS2---\nInput: inBuf= "); for (i = 0; i < inBufLen; i++) { fprintf(stderr, "%c", inBuf[i]); } fprintf(stderr,"\ninBufLen=%d\n", inBufLen);#endif rv = ssm_ConvertAsciiToUCS2(inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);#ifdef DEBUG outLen = *outBufLen; fprintf(stderr,"output: outBuf= "); for(i = 0; i < outLen; i++) { fprintf(stderr, "%c ", outBuf[i]); } fprintf(stderr,"\noutBuf= "); for(i = 0; i < outLen; i++) { fprintf(stderr,"%2x ", outBuf[i]); } fprintf(stderr,"\noutLen = %d\n", outLen);#endif /* DEBUG */ return rv; } PR_ASSERT(PR_FALSE); /* not supported yet */ return PR_FALSE;}PRBool SSM_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf, unsigned int inBufLen,unsigned char *outBuf, unsigned int maxOutBufLen, unsigned int *outBufLen){ PRBool retval;#ifdef DEBUG unsigned int i;#endif if(!inBuf || !outBuf || !outBufLen) { return PR_FALSE; } *outBufLen = 0;#ifdef DEBUG fprintf(stderr,"---UCS2_UTF8Conversion (%s) ---\nInput: \n", (toUnicode?"to UCS2":"to UTF8")); for(i=0; i< inBufLen; i++) { fprintf(stderr,"%c", (char) inBuf[i]); } fprintf(stderr,"\n"); for(i=0; i< inBufLen; i++) { fprintf(stderr,"%2x ", (char) inBuf[i]); } fprintf(stderr,"\n");#endif if(toUnicode) { retval = ssm_UTF8ToUCS2(inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen); } else { retval = ssm_UCS2ToUTF8(inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen); }#ifdef DEBUG fprintf(stderr,"Output: \n"); for(i=0; i< *outBufLen; i++) { fprintf(stderr,"%c", (char) outBuf[i]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -