p12dec.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 693 行 · 第 1/2 页
C
693 行
/* * 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 "pkcs12.h"#include "plarena.h"#include "secpkcs7.h"#include "p12local.h"#include "secoid.h"#include "secitem.h"#include "secport.h"#include "secasn1.h"#include "secder.h"#include "secerr.h"#include "cert.h"#include "certdb.h"#include "p12plcy.h"#include "p12.h"/* PFX extraction and validation routines *//* decode the DER encoded PFX item. if unable to decode, check to see if it * is an older PFX item. If that fails, assume the file was not a valid * pfx file. * the returned pfx structure should be destroyed using SEC_PKCS12DestroyPFX */static SEC_PKCS12PFXItem *sec_pkcs12_decode_pfx(SECItem *der_pfx){ SEC_PKCS12PFXItem *pfx; SECStatus rv; if(der_pfx == NULL) { return NULL; } /* allocate the space for a new PFX item */ pfx = sec_pkcs12_new_pfx(); if(pfx == NULL) { return NULL; } rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate, der_pfx); /* if a failure occurred, check for older version... * we also get rid of the old pfx structure, because we don't * know where it failed and what data in may contain */ if(rv != SECSuccess) { SEC_PKCS12DestroyPFX(pfx); pfx = sec_pkcs12_new_pfx(); if(pfx == NULL) { return NULL; } rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate_OLD, der_pfx); if(rv != SECSuccess) { PORT_SetError(SEC_ERROR_PKCS12_DECODING_PFX); PORT_FreeArena(pfx->poolp, PR_TRUE); return NULL; } pfx->old = PR_TRUE; SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac); SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt); } else { pfx->old = PR_FALSE; } /* convert bit string from bits to bytes */ pfx->macData.macSalt.len /= 8; return pfx;}/* validate the integrity MAC used in the PFX. The MAC is generated * per the PKCS 12 document. If the MAC is incorrect, it is most likely * due to an invalid password. * pwitem is the integrity password * pfx is the decoded pfx item */static PRBool sec_pkcs12_check_pfx_mac(SEC_PKCS12PFXItem *pfx, SECItem *pwitem){ SECItem *key = NULL, *mac = NULL, *data = NULL; SECItem *vpwd = NULL; SECOidTag algorithm; PRBool ret = PR_FALSE; if(pfx == NULL) { return PR_FALSE; } algorithm = SECOID_GetAlgorithmTag(&pfx->macData.safeMac.digestAlgorithm); switch(algorithm) { /* only SHA1 hashing supported as a MACing algorithm */ case SEC_OID_SHA1: if(pfx->old == PR_FALSE) { pfx->swapUnicode = PR_FALSE; }recheckUnicodePassword: vpwd = sec_pkcs12_create_virtual_password(pwitem, &pfx->macData.macSalt, pfx->swapUnicode); if(vpwd == NULL) { return PR_FALSE; } key = sec_pkcs12_generate_key_from_password(algorithm, &pfx->macData.macSalt, (pfx->old ? pwitem : vpwd)); /* free vpwd only for newer PFX */ if(vpwd) { SECITEM_ZfreeItem(vpwd, PR_TRUE); } if(key == NULL) { return PR_FALSE; } data = SEC_PKCS7GetContent(&pfx->authSafe); if(data == NULL) { break; } /* check MAC */ mac = sec_pkcs12_generate_mac(key, data, pfx->old); ret = PR_TRUE; if(mac) { SECItem *safeMac = &pfx->macData.safeMac.digest; if(SECITEM_CompareItem(mac, safeMac) != SECEqual) { /* if we encounter an invalid mac, lets invert the * password in case of unicode changes */ if(((!pfx->old) && pfx->swapUnicode) || (pfx->old)){ PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC); ret = PR_FALSE; } else { SECITEM_ZfreeItem(mac, PR_TRUE); pfx->swapUnicode = PR_TRUE; goto recheckUnicodePassword; } } SECITEM_ZfreeItem(mac, PR_TRUE); } else { ret = PR_FALSE; } break; default: PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM); ret = PR_FALSE; break; } /* let success fall through */ if(key != NULL) SECITEM_ZfreeItem(key, PR_TRUE); return ret;}/* check the validity of the pfx structure. we currently only support * password integrity mode, so we check the MAC. */static PRBool sec_pkcs12_validate_pfx(SEC_PKCS12PFXItem *pfx, SECItem *pwitem){ SECOidTag contentType; contentType = SEC_PKCS7ContentType(&pfx->authSafe); switch(contentType) { case SEC_OID_PKCS7_DATA: return sec_pkcs12_check_pfx_mac(pfx, pwitem); break; case SEC_OID_PKCS7_SIGNED_DATA: default: PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); break; } return PR_FALSE;}/* decode and return the valid PFX. if the PFX item is not valid, * NULL is returned. */static SEC_PKCS12PFXItem *sec_pkcs12_get_pfx(SECItem *pfx_data, SECItem *pwitem){ SEC_PKCS12PFXItem *pfx; PRBool valid_pfx; if((pfx_data == NULL) || (pwitem == NULL)) { return NULL; } pfx = sec_pkcs12_decode_pfx(pfx_data); if(pfx == NULL) { return NULL; } valid_pfx = sec_pkcs12_validate_pfx(pfx, pwitem); if(valid_pfx != PR_TRUE) { SEC_PKCS12DestroyPFX(pfx); pfx = NULL; } return pfx;}/* authenticated safe decoding, validation, and access routines *//* convert dogbert beta 3 authenticated safe structure to a post * beta three structure, so that we don't have to change more routines. */static SECStatussec_pkcs12_convert_old_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe){ SEC_PKCS12Baggage *baggage; SEC_PKCS12BaggageItem *bag; SECStatus rv = SECSuccess; if(asafe->old_baggage.espvks == NULL) { /* XXX should the ASN1 engine produce a single NULL element list * rather than setting the pointer to NULL? * There is no need to return an error -- assume that the list * was empty. */ return SECSuccess; } baggage = sec_pkcs12_create_baggage(asafe->poolp); if(!baggage) { return SECFailure; } bag = sec_pkcs12_create_external_bag(baggage); if(!bag) { return SECFailure; } PORT_Memcpy(&asafe->baggage, baggage, sizeof(SEC_PKCS12Baggage)); /* if there are shrouded keys, append them to the bag */ rv = SECSuccess; if(asafe->old_baggage.espvks[0] != NULL) { int nEspvk = 0; rv = SECSuccess; while((asafe->old_baggage.espvks[nEspvk] != NULL) && (rv == SECSuccess)) { rv = sec_pkcs12_append_shrouded_key(bag, asafe->old_baggage.espvks[nEspvk]); nEspvk++; } } return rv;} /* decodes the authenticated safe item. a return of NULL indicates * an error. however, the error will have occured either in memory * allocation or in decoding the authenticated safe. * * if an old PFX item has been found, we want to convert the * old authenticated safe to the new one. */static SEC_PKCS12AuthenticatedSafe *sec_pkcs12_decode_authenticated_safe(SEC_PKCS12PFXItem *pfx) { SECItem *der_asafe = NULL; SEC_PKCS12AuthenticatedSafe *asafe = NULL; SECStatus rv; if(pfx == NULL) { return NULL; } der_asafe = SEC_PKCS7GetContent(&pfx->authSafe); if(der_asafe == NULL) { /* XXX set error ? */ goto loser; } asafe = sec_pkcs12_new_asafe(pfx->poolp); if(asafe == NULL) { goto loser; } if(pfx->old == PR_FALSE) { rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, SEC_PKCS12AuthenticatedSafeTemplate, der_asafe); asafe->old = PR_FALSE; asafe->swapUnicode = pfx->swapUnicode; } else { /* handle beta exported files */ rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, SEC_PKCS12AuthenticatedSafeTemplate_OLD, der_asafe); asafe->safe = &(asafe->old_safe); rv = sec_pkcs12_convert_old_auth_safe(asafe); asafe->old = PR_TRUE; } if(rv != SECSuccess) { goto loser; } asafe->poolp = pfx->poolp; return asafe;loser:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?