cmssiginfo.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 872 行 · 第 1/2 页
C
872 行
/* * 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. *//* * CMS signerInfo methods. * * $Id: cmssiginfo.c,v 1.4 2000/06/20 16:28:57 chrisk%netscape.com Exp $ */#include "cmslocal.h"#include "cert.h"#include "key.h"#include "secasn1.h"#include "secitem.h"#include "secoid.h"#include "pk11func.h"#include "prtime.h"#include "secerr.h"#include "cryptohi.h"#include "smime.h"/* ============================================================================= * SIGNERINFO */NSSCMSSignerInfo *NSS_CMSSignerInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert, SECOidTag digestalgtag){ void *mark; NSSCMSSignerInfo *signerinfo; int version; PLArenaPool *poolp; poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo)); if (signerinfo == NULL) { PORT_ArenaRelease(poolp, mark); return NULL; } if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL) goto loser; signerinfo->cmsg = cmsg; signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN; /* hardcoded for now */ if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) goto loser; /* set version right now */ version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN; /* RFC2630 5.3 "version is the syntax version number. If the .... " */ if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY; (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version); if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return signerinfo;loser: PORT_ArenaRelease(poolp, mark); return NULL;}/* * NSS_CMSSignerInfo_Destroy - destroy a SignerInfo data structure */voidNSS_CMSSignerInfo_Destroy(NSSCMSSignerInfo *si){ if (si->cert != NULL) CERT_DestroyCertificate(si->cert); /* XXX storage ??? */}/* * NSS_CMSSignerInfo_Sign - sign something * */SECStatusNSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest, SECItem *contentType){ CERTCertificate *cert; SECKEYPrivateKey *privkey = NULL; SECOidTag digestalgtag; SECOidTag signalgtag; SECItem signature = { 0 }; SECStatus rv; PLArenaPool *poolp, *tmppoolp; PORT_Assert (digest != NULL); poolp = signerinfo->cmsg->poolp; cert = signerinfo->cert; if ((privkey = PK11_FindKeyByAnyCert(cert, signerinfo->cmsg->pwfn_arg)) == NULL) goto loser; digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo); /* * XXX I think there should be a cert-level interface for this, * so that I do not have to know about subjectPublicKeyInfo... */ signalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); /* Fortezza MISSI have weird signature formats. Map them to standard DSA formats */ signalgtag = PK11_FortezzaMapSig(signalgtag); if (signerinfo->authAttr != NULL) { SECItem encoded_attrs; /* find and fill in the message digest attribute. */ rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE); if (rv != SECSuccess) goto loser; if (contentType != NULL) { /* if the caller wants us to, find and fill in the content type attribute. */ rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE); if (rv != SECSuccess) goto loser; } if ((tmppoolp = PORT_NewArena (1024)) == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } /* * Before encoding, reorder the attributes so that when they * are encoded, they will be conforming DER, which is required * to have a specific order and that is what must be used for * the hash/signature. We do this here, rather than building * it into EncodeAttributes, because we do not want to do * such reordering on incoming messages (which also uses * EncodeAttributes) or our old signatures (and other "broken" * implementations) will not verify. So, we want to guarantee * that we send out good DER encodings of attributes, but not * to expect to receive them. */ if (NSS_CMSAttributeArray_Reorder(signerinfo->authAttr) != SECSuccess) goto loser; encoded_attrs.data = NULL; encoded_attrs.len = 0; if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr), &encoded_attrs) == NULL) goto loser; rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len, privkey, NSS_CMSUtil_MakeSignatureAlgorithm(digestalgtag, signalgtag)); PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */ } else { rv = SGN_Digest(privkey, digestalgtag, &signature, digest); } SECKEY_DestroyPrivateKey(privkey); privkey = NULL; if (rv != SECSuccess) goto loser; if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) != SECSuccess) goto loser; SECITEM_FreeItem(&signature, PR_FALSE); if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), signalgtag, NULL) != SECSuccess) goto loser; return SECSuccess;loser: if (signature.len != 0) SECITEM_FreeItem (&signature, PR_FALSE); if (privkey) SECKEY_DestroyPrivateKey(privkey); return SECFailure;}SECStatusNSS_CMSSignerInfo_VerifyCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb, SECCertUsage certusage){ CERTCertificate *cert; int64 stime; if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb)) == NULL) { signerinfo->verificationStatus = NSSCMSVS_SigningCertNotFound; return SECFailure; } /* * Get and convert the signing time; if available, it will be used * both on the cert verification and for importing the sender * email profile. */ if (NSS_CMSSignerInfo_GetSigningTime (signerinfo, &stime) != SECSuccess) stime = PR_Now(); /* not found or conversion failed, so check against now */ /* * XXX This uses the signing time, if available. Additionally, we * might want to, if there is no signing time, get the message time * from the mail header itself, and use that. That would require * a change to our interface though, and for S/MIME callers to pass * in a time (and for non-S/MIME callers to pass in nothing, or * maybe make them pass in the current time, always?). */ if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, stime, signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) { signerinfo->verificationStatus = NSSCMSVS_SigningCertNotTrusted; return SECFailure; } return SECSuccess;}/* * NSS_CMSSignerInfo_Verify - verify the signature of a single SignerInfo * * Just verifies the signature. The assumption is that verification of the certificate * is done already. */SECStatusNSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo, SECItem *digest, SECItem *contentType){ SECKEYPublicKey *publickey = NULL; NSSCMSAttribute *attr; SECItem encoded_attrs; CERTCertificate *cert; NSSCMSVerificationStatus vs = NSSCMSVS_Unverified; PLArenaPool *poolp; if (signerinfo == NULL) return SECFailure; /* NSS_CMSSignerInfo_GetSigningCertificate will fail if 2nd parm is NULL and */ /* cert has not been verified */ if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, NULL)) == NULL) { vs = NSSCMSVS_SigningCertNotFound; goto loser; } if ((publickey = CERT_ExtractPublicKey(cert)) == NULL) { vs = NSSCMSVS_ProcessingError; goto loser; } /* * XXX This may not be the right set of algorithms to check. * I'd prefer to trust that just calling VFY_Verify{Data,Digest} * would do the right thing (and set an error if it could not); * then additional algorithms could be handled by that code * and we would Just Work. So this check should just be removed, * but not until the VFY code is better at setting errors. */ switch (SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg))) { case SEC_OID_PKCS1_RSA_ENCRYPTION: case SEC_OID_ANSIX9_DSA_SIGNATURE: case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: /* ok */ break; case SEC_OID_UNKNOWN: vs = NSSCMSVS_SignatureAlgorithmUnknown; goto loser; default: vs = NSSCMSVS_SignatureAlgorithmUnsupported; goto loser; } if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) { if (contentType) { /* * Check content type * * RFC2630 sez that if there are any authenticated attributes, * then there must be one for content type which matches the * content type of the content being signed, and there must * be one for message digest which matches our message digest. * So check these things first. */ if ((attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE)) == NULL) { vs = NSSCMSVS_MalformedSignature; goto loser; } if (NSS_CMSAttribute_CompareValue(attr, contentType) == PR_FALSE) { vs = NSSCMSVS_MalformedSignature; goto loser; } } /* * Check digest */ if ((attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE)) == NULL) { vs = NSSCMSVS_MalformedSignature; goto loser; } if (NSS_CMSAttribute_CompareValue(attr, digest) == PR_FALSE) { vs = NSSCMSVS_DigestMismatch; goto loser; } if ((poolp = PORT_NewArena (1024)) == NULL) { vs = NSSCMSVS_ProcessingError; goto loser; } /* * Check signature * * The signature is based on a digest of the DER-encoded authenticated * attributes. So, first we encode and then we digest/verify. * we trust the decoder to have the attributes in the right (sorted) order */ encoded_attrs.data = NULL; encoded_attrs.len = 0; if (NSS_CMSAttributeArray_Encode(poolp, &(signerinfo->authAttr), &encoded_attrs) == NULL || encoded_attrs.data == NULL || encoded_attrs.len == 0) { vs = NSSCMSVS_ProcessingError; goto loser; } vs = (VFY_VerifyData (encoded_attrs.data, encoded_attrs.len, publickey, &(signerinfo->encDigest), SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg)), signerinfo->cmsg->pwfn_arg) != SECSuccess) ? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature; PORT_FreeArena(poolp, PR_FALSE); /* awkward memory management :-( */ } else { SECItem *sig; /* No authenticated attributes. The signature is based on the plain message digest. */ sig = &(signerinfo->encDigest); if (sig->len == 0) goto loser; vs = (VFY_VerifyDigest(digest, publickey, sig, SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg)), signerinfo->cmsg->pwfn_arg) != SECSuccess) ? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature; } if (vs == NSSCMSVS_BadSignature) { /* * XXX Change the generic error into our specific one, because * in that case we get a better explanation out of the Security * Advisor. This is really a bug in our error strings (the * "generic" error has a lousy/wrong message associated with it * which assumes the signature verification was done for the * purposes of checking the issuer signature on a certificate) * but this is at least an easy workaround and/or in the * Security Advisor, which specifically checks for the error * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation * in that case but does not similarly check for * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would * probably say the wrong thing in the case that it *was* the * certificate signature check that failed during the cert * verification done above. Our error handling is really a mess. */ if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE) PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); } if (publickey != NULL) SECKEY_DestroyPublicKey (publickey); signerinfo->verificationStatus = vs; return (vs == NSSCMSVS_GoodSignature) ? SECSuccess : SECFailure;loser: if (publickey != NULL) SECKEY_DestroyPublicKey (publickey); signerinfo->verificationStatus = vs; PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); return SECFailure;}NSSCMSVerificationStatusNSS_CMSSignerInfo_GetVerificationStatus(NSSCMSSignerInfo *signerinfo){ return signerinfo->verificationStatus;}SECOidData *NSS_CMSSignerInfo_GetDigestAlg(NSSCMSSignerInfo *signerinfo){ return SECOID_FindOID (&(signerinfo->digestAlg.algorithm));}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?