CERTUserNotice * CERT_DecodeUserNotice(SECItem *noticeItem) { PLArenaPool *arena = NULL; SECStatus rv; CERTUserNotice *userNotice; SECItem newNoticeItem; /* make a new arena */ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( !arena ) { goto loser; } /* allocate the userNotice structure */ userNotice = (CERTUserNotice *)PORT_ArenaZAlloc(arena, sizeof(CERTUserNotice)); if ( userNotice == NULL ) { goto loser; } userNotice->arena = arena; /* copy the DER into the arena, since Quick DER returns data that points into the DER input, which may get freed by the caller */ rv = SECITEM_CopyItem(arena, &newNoticeItem, noticeItem); if ( rv != SECSuccess ) { goto loser; } /* decode the user notice */ rv = SEC_QuickDERDecodeItem(arena, userNotice, CERT_UserNoticeTemplate, &newNoticeItem); if ( rv != SECSuccess ) { goto loser; } if (userNotice->derNoticeReference.data != NULL) { rv = SEC_QuickDERDecodeItem(arena, &userNotice->noticeReference, CERT_NoticeReferenceTemplate, &userNotice->derNoticeReference); if (rv == SECFailure) { goto loser; } } return(userNotice); loser: if ( arena != NULL ) { PORT_FreeArena(arena, PR_FALSE); } return(NULL); }
/* What the hell? * https://mxr.mozilla.org/security/source/security/nss/lib/cryptohi/seckey.c#1346 */ SECKEYPublicKey *my_SECKEY_DecodeDERPublicKey (SECItem *pubkder) { PRArenaPool *arena; SECKEYPublicKey *pubk; SECStatus rv; SECItem newPubkder; arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { return NULL; } pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey)); if (pubk != NULL) { pubk->arena = arena; pubk->pkcs11Slot = NULL; pubk->pkcs11ID = 0; pubk->u.rsa.modulus.type = siUnsignedInteger; pubk->u.rsa.publicExponent.type = siUnsignedInteger; /* copy the DER into the arena, since Quick DER returns data that points into the DER input, which may get freed by the caller */ rv = SECITEM_CopyItem(arena, &newPubkder, pubkder); if ( rv == SECSuccess ) { rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_RSAPublicKeyTemplate,&newPubkder); } if (rv == SECSuccess) return pubk; //SECKEY_DestroyPublicKey (pubk); } PORT_FreeArena (arena, PR_FALSE); return NULL; }
SECStatus CERT_DecodeInhibitAnyExtension (CERTCertificateInhibitAny *decodedValue, SECItem *encodedValue) { CERTCertificateInhibitAny decodeContext; PLArenaPool *arena = NULL; SECStatus rv = SECSuccess; /* make a new arena */ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); if ( !arena ) { return SECFailure; } do { /* decode the policy mappings */ decodeContext.inhibitAnySkipCerts.type = siUnsignedInteger; rv = SEC_QuickDERDecodeItem(arena, &decodeContext, CERT_InhibitAnyTemplate, encodedValue); if ( rv != SECSuccess ) { break; } *(PRInt32 *)decodedValue->inhibitAnySkipCerts.data = DER_GetInteger(&decodeContext.inhibitAnySkipCerts); } while (0); PORT_FreeArena(arena, PR_FALSE); return(rv); }
SECStatus CERT_FindCRLNumberExten (PRArenaPool *arena, CERTCrl *crl, SECItem *value) { SECItem encodedExtenValue; SECItem *tmpItem = NULL; SECStatus rv; void *mark = NULL; encodedExtenValue.data = NULL; encodedExtenValue.len = 0; rv = cert_FindExtension(crl->extensions, SEC_OID_X509_CRL_NUMBER, &encodedExtenValue); if ( rv != SECSuccess ) return (rv); mark = PORT_ArenaMark(arena); tmpItem = SECITEM_ArenaDupItem(arena, &encodedExtenValue); if (tmpItem) { rv = SEC_QuickDERDecodeItem (arena, value, SEC_ASN1_GET(SEC_IntegerTemplate), tmpItem); } else { rv = SECFailure; } PORT_Free (encodedExtenValue.data); if (rv == SECFailure) { PORT_ArenaRelease(arena, mark); } else { PORT_ArenaUnmark(arena, mark); } return (rv); }
CERTPrivKeyUsagePeriod * CERT_DecodePrivKeyUsagePeriodExtension(PLArenaPool *arena, SECItem *extnValue) { SECStatus rv; CERTPrivKeyUsagePeriod *pPeriod; SECItem newExtnValue; /* allocate the certificate policies structure */ pPeriod = PORT_ArenaZNew(arena, CERTPrivKeyUsagePeriod); if ( pPeriod == NULL ) { goto loser; } pPeriod->arena = arena; /* copy the DER into the arena, since Quick DER returns data that points into the DER input, which may get freed by the caller */ rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue); if ( rv != SECSuccess ) { goto loser; } rv = SEC_QuickDERDecodeItem(arena, pPeriod, CERTPrivateKeyUsagePeriodTemplate, &newExtnValue); if ( rv != SECSuccess ) { goto loser; } return pPeriod; loser: return NULL; }
/* * NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference - * find cert marked by EncryptionKeyPreference attribute * * "certdb" - handle for the cert database to look in * "DERekp" - DER-encoded value of S/MIME Encryption Key Preference attribute * * if certificate is supposed to be found among the message's included certificates, * they are assumed to have been imported already. */ CERTCertificate * NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(CERTCertDBHandle *certdb, SECItem *DERekp) { PLArenaPool *tmppoolp = NULL; CERTCertificate *cert = NULL; NSSSMIMEEncryptionKeyPreference ekp; tmppoolp = PORT_NewArena(1024); if (tmppoolp == NULL) return NULL; /* decode DERekp */ if (SEC_QuickDERDecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template, DERekp) != SECSuccess) goto loser; /* find cert */ switch (ekp.selector) { case NSSSMIMEEncryptionKeyPref_IssuerSN: cert = CERT_FindCertByIssuerAndSN(certdb, ekp.id.issuerAndSN); break; case NSSSMIMEEncryptionKeyPref_RKeyID: case NSSSMIMEEncryptionKeyPref_SubjectKeyID: /* XXX not supported yet - we need to be able to look up certs by SubjectKeyID */ break; default: PORT_Assert(0); } loser: if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); return cert; }
CERTGeneralName * CERT_DecodeAltNameExtension(PRArenaPool *reqArena, SECItem *EncodedAltName) { SECStatus rv = SECSuccess; CERTAltNameEncodedContext encodedContext; SECItem* newEncodedAltName; if (!reqArena) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } newEncodedAltName = SECITEM_ArenaDupItem(reqArena, EncodedAltName); if (!newEncodedAltName) { return NULL; } encodedContext.encodedGenName = NULL; PORT_Memset(&encodedContext, 0, sizeof(CERTAltNameEncodedContext)); rv = SEC_QuickDERDecodeItem (reqArena, &encodedContext, CERT_GeneralNamesTemplate, newEncodedAltName); if (rv == SECFailure) { goto loser; } if (encodedContext.encodedGenName && encodedContext.encodedGenName[0]) return cert_DecodeGeneralNames(reqArena, encodedContext.encodedGenName); /* Extension contained an empty GeneralNames sequence */ /* Treat as extension not found */ PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND); loser: return NULL; }
SGNDigestInfo * SGN_DecodeDigestInfo(SECItem *didata) { PLArenaPool *arena; SGNDigestInfo *di; SECStatus rv = SECFailure; SECItem diCopy = {siBuffer, NULL, 0}; arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); if(arena == NULL) return NULL; rv = SECITEM_CopyItem(arena, &diCopy, didata); if (rv != SECSuccess) { PORT_FreeArena(arena, PR_FALSE); return NULL; } di = (SGNDigestInfo *)PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo)); if (di != NULL) { di->arena = arena; rv = SEC_QuickDERDecodeItem(arena, di, sgn_DigestInfoTemplate, &diCopy); } if ((di == NULL) || (rv != SECSuccess)) { PORT_FreeArena(arena, PR_FALSE); di = NULL; } return di; }
/* * get the value of the X.509 v3 Key Usage Extension */ SECStatus CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem) { SECStatus rv; SECItem encodedValue = {siBuffer, NULL, 0 }; SECItem decodedValue = {siBuffer, NULL, 0 }; rv = cert_FindExtension (cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID, &encodedValue); if (rv == SECSuccess) { PLArenaPool * tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (tmpArena) { rv = SEC_QuickDERDecodeItem(tmpArena, &decodedValue, SEC_ASN1_GET(SEC_OctetStringTemplate), &encodedValue); if (rv == SECSuccess) { rv = SECITEM_CopyItem(NULL, retItem, &decodedValue); } PORT_FreeArena(tmpArena, PR_FALSE); } else { rv = SECFailure; } } SECITEM_FreeItem(&encodedValue, PR_FALSE); return rv; }
// 4.2.1.3. Key Usage (id-ce-keyUsage) // Modeled after GetKeyUsage in certdb.c Result CheckKeyUsage(EndEntityOrCA endEntityOrCA, bool isTrustAnchor, const SECItem* encodedKeyUsage, KeyUsages requiredKeyUsagesIfPresent, PLArenaPool* arena) { if (!encodedKeyUsage) { // TODO: Reject certificates that are being used to verify certificate // signatures unless the certificate is a trust anchor, to reduce the // chances of an end-entity certificate being abused as a CA certificate. // if (endEntityOrCA == MustBeCA && !isTrustAnchor) { // return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); // } // // TODO: Users may configure arbitrary certificates as trust anchors, not // just roots. We should only allow a certificate without a key usage to be // used as a CA when it is self-issued and self-signed. return Success; } SECItem tmpItem; Result rv = MapSECStatus(SEC_QuickDERDecodeItem(arena, &tmpItem, SEC_ASN1_GET(SEC_BitStringTemplate), encodedKeyUsage)); if (rv != Success) { return rv; } // TODO XXX: Why is tmpItem.len > 1? KeyUsages allowedKeyUsages = tmpItem.data[0]; if ((allowedKeyUsages & requiredKeyUsagesIfPresent) != requiredKeyUsagesIfPresent) { return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); } if (endEntityOrCA == MustBeCA) { // "If the keyUsage extension is present, then the subject public key // MUST NOT be used to verify signatures on certificates or CRLs unless // the corresponding keyCertSign or cRLSign bit is set." if ((allowedKeyUsages & KU_KEY_CERT_SIGN) == 0) { return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); } } else { // "The keyCertSign bit is asserted when the subject public key is // used for verifying signatures on public key certificates. If the // keyCertSign bit is asserted, then the cA bit in the basic // constraints extension (Section 4.2.1.9) MUST also be asserted." // TODO XXX: commented out to match classic NSS behavior. //if ((allowedKeyUsages & KU_KEY_CERT_SIGN) != 0) { // // XXX: better error code. // return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE); //} } return Success; }
SECStatus CERT_DecodePolicyConstraintsExtension (CERTCertificatePolicyConstraints *decodedValue, const SECItem *encodedValue) { CERTCertificatePolicyConstraints decodeContext; PLArenaPool *arena = NULL; SECStatus rv = SECSuccess; /* initialize so we can tell when an optional component is omitted */ PORT_Memset(&decodeContext, 0, sizeof(decodeContext)); /* make a new arena */ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); if (!arena) { return SECFailure; } do { /* decode the policy constraints */ rv = SEC_QuickDERDecodeItem(arena, &decodeContext, CERT_PolicyConstraintsTemplate, encodedValue); if ( rv != SECSuccess ) { break; } if (decodeContext.explicitPolicySkipCerts.len == 0) { *(PRInt32 *)decodedValue->explicitPolicySkipCerts.data = -1; } else { *(PRInt32 *)decodedValue->explicitPolicySkipCerts.data = DER_GetInteger(&decodeContext.explicitPolicySkipCerts); } if (decodeContext.inhibitMappingSkipCerts.len == 0) { *(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data = -1; } else { *(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data = DER_GetInteger(&decodeContext.inhibitMappingSkipCerts); } if ((*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data == PR_INT32_MIN) || (*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data == PR_INT32_MAX) || (*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data == PR_INT32_MIN) || (*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data == PR_INT32_MAX)) { rv = SECFailure; } } while (0); PORT_FreeArena(arena, PR_FALSE); return(rv); }
SECStatus CERT_DecodeBasicConstraintValue (CERTBasicConstraints *value, SECItem *encodedValue) { EncodedContext decodeContext; PRArenaPool *our_pool; SECStatus rv = SECSuccess; do { PORT_Memset (&decodeContext, 0, sizeof (decodeContext)); /* initialize the value just in case we got "0x30 00", or when the pathLenConstraint is omitted. */ decodeContext.isCA.data =&hexFalse; decodeContext.isCA.len = 1; our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); if (our_pool == NULL) { PORT_SetError (SEC_ERROR_NO_MEMORY); GEN_BREAK (SECFailure); } rv = SEC_QuickDERDecodeItem (our_pool, &decodeContext, CERTBasicConstraintsTemplate, encodedValue); if (rv == SECFailure) break; value->isCA = decodeContext.isCA.data ? (PRBool)(decodeContext.isCA.data[0] != 0) : PR_FALSE; if (decodeContext.pathLenConstraint.data == NULL) { /* if the pathLenConstraint is not encoded, and the current setting is CA, then the pathLenConstraint should be set to a negative number for unlimited certificate path. */ if (value->isCA) value->pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; } else if (value->isCA) { long len = DER_GetInteger (&decodeContext.pathLenConstraint); if (len < 0 || len == LONG_MAX) { PORT_SetError (SEC_ERROR_BAD_DER); GEN_BREAK (SECFailure); } value->pathLenConstraint = len; } else { /* here we get an error where the subject is not a CA, but the pathLenConstraint is set */ PORT_SetError (SEC_ERROR_BAD_DER); GEN_BREAK (SECFailure); break; } } while (0); PORT_FreeArena (our_pool, PR_FALSE); return (rv); }
/* * get the value of a string type extension */ char * CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag) { SECItem wrapperItem, tmpItem = {siBuffer,0}; SECStatus rv; PLArenaPool *arena = NULL; char *retstring = NULL; wrapperItem.data = NULL; tmpItem.data = NULL; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( ! arena ) { goto loser; } rv = cert_FindExtension(cert->extensions, oidtag, &wrapperItem); if ( rv != SECSuccess ) { goto loser; } rv = SEC_QuickDERDecodeItem(arena, &tmpItem, SEC_ASN1_GET(SEC_IA5StringTemplate), &wrapperItem); if ( rv != SECSuccess ) { goto loser; } retstring = (char *)PORT_Alloc(tmpItem.len + 1 ); if ( retstring == NULL ) { goto loser; } PORT_Memcpy(retstring, tmpItem.data, tmpItem.len); retstring[tmpItem.len] = '\0'; loser: if ( arena ) { PORT_FreeArena(arena, PR_FALSE); } if ( wrapperItem.data ) { PORT_Free(wrapperItem.data); } return(retstring); }
CERTAuthKeyID * CERT_DecodeAuthKeyID (PLArenaPool *arena, const SECItem *encodedValue) { CERTAuthKeyID * value = NULL; SECStatus rv = SECFailure; void * mark; SECItem newEncodedValue; PORT_Assert (arena); do { mark = PORT_ArenaMark (arena); value = (CERTAuthKeyID*)PORT_ArenaZAlloc (arena, sizeof (*value)); if (value == NULL) break; value->DERAuthCertIssuer = NULL; /* copy the DER into the arena, since Quick DER returns data that points into the DER input, which may get freed by the caller */ rv = SECITEM_CopyItem(arena, &newEncodedValue, encodedValue); if ( rv != SECSuccess ) { break; } rv = SEC_QuickDERDecodeItem (arena, value, CERTAuthKeyIDTemplate, &newEncodedValue); if (rv != SECSuccess) break; value->authCertIssuer = cert_DecodeGeneralNames (arena, value->DERAuthCertIssuer); if (value->authCertIssuer == NULL) break; /* what if the general name contains other format but not URI ? hl */ if ((value->authCertSerialNumber.data && !value->authCertIssuer) || (!value->authCertSerialNumber.data && value->authCertIssuer)){ PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); break; } } while (0); if (rv != SECSuccess) { PORT_ArenaRelease (arena, mark); return ((CERTAuthKeyID *)NULL); } PORT_ArenaUnmark(arena, mark); return (value); }
CERTOidSequence * CERT_DecodeOidSequence(const SECItem *seqItem) { PLArenaPool *arena = NULL; SECStatus rv; CERTOidSequence *oidSeq; SECItem newSeqItem; /* make a new arena */ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( !arena ) { goto loser; } /* allocate the userNotice structure */ oidSeq = (CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence)); if ( oidSeq == NULL ) { goto loser; } oidSeq->arena = arena; /* copy the DER into the arena, since Quick DER returns data that points into the DER input, which may get freed by the caller */ rv = SECITEM_CopyItem(arena, &newSeqItem, seqItem); if ( rv != SECSuccess ) { goto loser; } /* decode the user notice */ rv = SEC_QuickDERDecodeItem(arena, oidSeq, CERT_OidSeqTemplate, &newSeqItem); if ( rv != SECSuccess ) { goto loser; } return(oidSeq); loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } return(NULL); }
CERTCertificatePolicyMappings * CERT_DecodePolicyMappingsExtension(SECItem *extnValue) { PLArenaPool *arena = NULL; SECStatus rv; CERTCertificatePolicyMappings *mappings; SECItem newExtnValue; /* make a new arena */ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( !arena ) { goto loser; } /* allocate the policy mappings structure */ mappings = (CERTCertificatePolicyMappings *) PORT_ArenaZAlloc(arena, sizeof(CERTCertificatePolicyMappings)); if ( mappings == NULL ) { goto loser; } mappings->arena = arena; /* copy the DER into the arena, since Quick DER returns data that points into the DER input, which may get freed by the caller */ rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue); if ( rv != SECSuccess ) { goto loser; } /* decode the policy mappings */ rv = SEC_QuickDERDecodeItem (arena, mappings, CERT_PolicyMappingsTemplate, &newExtnValue); if ( rv != SECSuccess ) { goto loser; } return(mappings); loser: if ( arena != NULL ) { PORT_FreeArena(arena, PR_FALSE); } return(NULL); }
SECStatus CERT_FindCRLEntryReasonExten (CERTCrlEntry *crlEntry, CERTCRLEntryReasonCode *value) { SECItem wrapperItem = {siBuffer,0}; SECItem tmpItem = {siBuffer,0}; SECStatus rv; PRArenaPool *arena = NULL; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( ! arena ) { return(SECFailure); } rv = cert_FindExtension(crlEntry->extensions, SEC_OID_X509_REASON_CODE, &wrapperItem); if ( rv != SECSuccess ) { goto loser; } rv = SEC_QuickDERDecodeItem(arena, &tmpItem, SEC_ASN1_GET(SEC_EnumeratedTemplate), &wrapperItem); if ( rv != SECSuccess ) { goto loser; } *value = (CERTCRLEntryReasonCode) DER_GetInteger(&tmpItem); loser: if ( arena ) { PORT_FreeArena(arena, PR_FALSE); } if ( wrapperItem.data ) { PORT_Free(wrapperItem.data); } return (rv); }
NSSCMSRecipientInfo * nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, NSSCMSRecipientIDSelector type, CERTCertificate *cert, SECKEYPublicKey *pubKey, SECItem *subjKeyID, void* pwfn_arg, SECItem* DERinput) { NSSCMSRecipientInfo *ri; void *mark; SECOidTag certalgtag; SECStatus rv = SECSuccess; NSSCMSRecipientEncryptedKey *rek; NSSCMSOriginatorIdentifierOrKey *oiok; unsigned long version; SECItem *dummy; PLArenaPool *poolp; CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; NSSCMSRecipientIdentifier *rid; extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; if (!cmsg) { /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc * and a private arena pool */ cmsg = NSS_CMSMessage_Create(NULL); cmsg->pwfn_arg = pwfn_arg; /* mark it as a special cms message */ cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent; } poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo)); if (ri == NULL) goto loser; ri->cmsg = cmsg; if (DERinput) { /* decode everything from DER */ SECItem newinput; SECStatus rv = SECITEM_CopyItem(poolp, &newinput, DERinput); if (SECSuccess != rv) goto loser; rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput); if (SECSuccess != rv) goto loser; } switch (type) { case NSSCMSRecipientID_IssuerSN: { ri->cert = CERT_DupCertificate(cert); if (NULL == ri->cert) goto loser; spki = &(cert->subjectPublicKeyInfo); break; } case NSSCMSRecipientID_SubjectKeyID: { PORT_Assert(pubKey); spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey); break; } case NSSCMSRecipientID_BrandNew: goto done; break; default: /* unkown type */ goto loser; break; } certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm)); rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans; rid->identifierType = type; if (type == NSSCMSRecipientID_IssuerSN) { rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); if (rid->id.issuerAndSN == NULL) { break; } } else if (type == NSSCMSRecipientID_SubjectKeyID){ NSSCMSKeyTransRecipientInfoEx *riExtra; rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem); if (rid->id.subjectKeyID == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID); if (rid->id.subjectKeyID->data == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } riExtra = &ri->ri.keyTransRecipientInfoEx; riExtra->version = 0; riExtra->pubKey = SECKEY_CopyPublicKey(pubKey); if (riExtra->pubKey == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ PORT_Assert(type == NSSCMSRecipientID_IssuerSN); if (type != NSSCMSRecipientID_IssuerSN) { rv = SECFailure; break; } /* a key agreement op */ ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree; if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { rv = SECFailure; break; } /* we do not support the case where multiple recipients * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys * in this case, we would need to walk all the recipientInfos, take the * ones that do KeyAgreement algorithms and join them, algorithm by algorithm * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ /* only epheremal-static Diffie-Hellman is supported for now * this is the only form of key agreement that provides potential anonymity * of the sender, plus we do not have to include certs in the message */ /* force single recipientEncryptedKey for now */ if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) { rv = SECFailure; break; } /* hardcoded IssuerSN choice for now */ rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN; if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); /* see RFC2630 12.3.1.1 */ oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey; rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, (void *)rek); break; default: /* other algorithms not supported yet */ /* NOTE that we do not support any KEK algorithm */ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); rv = SECFailure; break; } if (rv == SECFailure) goto loser; /* set version */ switch (ri->recipientInfoType) { case NSSCMSRecipientInfoID_KeyTrans: if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN) version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; else version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); if (dummy == NULL) goto loser; break; case NSSCMSRecipientInfoID_KeyAgree: dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; case NSSCMSRecipientInfoID_KEK: /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), NSS_CMS_KEK_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; } done: PORT_ArenaUnmark (poolp, mark); if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); return ri; loser: if (ri && ri->cert) { CERT_DestroyCertificate(ri->cert); } if (freeSpki) { SECKEY_DestroySubjectPublicKeyInfo(freeSpki); } PORT_ArenaRelease (poolp, mark); if (cmsg->contentInfo.contentTypeTag == &fakeContent) { NSS_CMSMessage_Destroy(cmsg); } return NULL; }
static CERTCertificatePolicies * secu_DecodeCertificatePoliciesExtension(SECItem *extnValue) { PRArenaPool *arena = NULL; SECStatus rv; CERTCertificatePolicies *policies; CERTPolicyInfo **policyInfos, *policyInfo; CERTPolicyQualifier **policyQualifiers, *policyQualifier; SECItem newExtnValue; /* make a new arena */ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( !arena ) { goto loser; } /* allocate the certifiate policies structure */ policies = PORT_ArenaZNew(arena, CERTCertificatePolicies); if ( policies == NULL ) { goto loser; } policies->arena = arena; /* copy the DER into the arena, since Quick DER returns data that points into the DER input, which may get freed by the caller */ rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue); if ( rv != SECSuccess ) { goto loser; } /* decode the policy info */ rv = SEC_QuickDERDecodeItem(arena, policies, secu_CertificatePoliciesTemplate, &newExtnValue); if ( rv != SECSuccess ) { goto loser; } /* initialize the oid tags */ policyInfos = policies->policyInfos; while (policyInfos != NULL && *policyInfos != NULL ) { policyInfo = *policyInfos; policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID); policyQualifiers = policyInfo->policyQualifiers; while ( policyQualifiers && *policyQualifiers != NULL ) { policyQualifier = *policyQualifiers; policyQualifier->oid = SECOID_FindOIDTag(&policyQualifier->qualifierID); policyQualifiers++; } policyInfos++; } return(policies); loser: if ( arena != NULL ) { PORT_FreeArena(arena, PR_FALSE); } return(NULL); }
SECStatus PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, SECKEYPrivateKeyInfo *pki, SECItem *nickname, SECItem *publicValue, PRBool isPerm, PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey **privk, void *wincx) { SECStatus rv = SECFailure; SECKEYRawPrivateKey *lpk = NULL; const SEC_ASN1Template *keyTemplate, *paramTemplate; void *paramDest = NULL; PLArenaPool *arena = NULL; arena = PORT_NewArena(2048); if (!arena) { return SECFailure; } /* need to change this to use RSA/DSA keys */ lpk = (SECKEYRawPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(SECKEYRawPrivateKey)); if (lpk == NULL) { goto loser; } lpk->arena = arena; switch (SECOID_GetAlgorithmTag(&pki->algorithm)) { case SEC_OID_PKCS1_RSA_ENCRYPTION: prepare_rsa_priv_key_export_for_asn1(lpk); keyTemplate = SECKEY_RSAPrivateKeyExportTemplate; paramTemplate = NULL; paramDest = NULL; lpk->keyType = rsaKey; break; case SEC_OID_ANSIX9_DSA_SIGNATURE: prepare_dsa_priv_key_export_for_asn1(lpk); keyTemplate = SECKEY_DSAPrivateKeyExportTemplate; paramTemplate = SECKEY_PQGParamsTemplate; paramDest = &(lpk->u.dsa.params); lpk->keyType = dsaKey; break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: if (!publicValue) { goto loser; } prepare_dh_priv_key_export_for_asn1(lpk); keyTemplate = SECKEY_DHPrivateKeyExportTemplate; paramTemplate = NULL; paramDest = NULL; lpk->keyType = dhKey; break; case SEC_OID_ANSIX962_EC_PUBLIC_KEY: prepare_ec_priv_key_export_for_asn1(lpk); keyTemplate = SECKEY_ECPrivateKeyExportTemplate; paramTemplate = NULL; paramDest = NULL; lpk->keyType = ecKey; break; default: keyTemplate = NULL; paramTemplate = NULL; paramDest = NULL; break; } if (!keyTemplate) { goto loser; } /* decode the private key and any algorithm parameters */ rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey); if (rv != SECSuccess) { goto loser; } if (lpk->keyType == ecKey) { /* Convert length in bits to length in bytes. */ lpk->u.ec.publicValue.len >>= 3; /* Always override curveOID, we're ignoring any given value. */ rv = SECITEM_CopyItem(arena, &lpk->u.ec.curveOID, &pki->algorithm.parameters); if (rv != SECSuccess) { goto loser; } }
/* find a URL extension in the cert or its CA * apply the base URL string if it exists */ char * CERT_FindCertURLExtension(CERTCertificate *cert, int tag, int catag) { SECStatus rv; SECItem urlitem = {siBuffer,0}; SECItem baseitem = {siBuffer,0}; SECItem urlstringitem = {siBuffer,0}; SECItem basestringitem = {siBuffer,0}; PRArenaPool *arena = NULL; PRBool hasbase; char *urlstring; char *str; int len; unsigned int i; urlstring = NULL; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( ! arena ) { goto loser; } hasbase = PR_FALSE; rv = cert_FindExtension(cert->extensions, tag, &urlitem); if ( rv == SECSuccess ) { rv = cert_FindExtension(cert->extensions, SEC_OID_NS_CERT_EXT_BASE_URL, &baseitem); if ( rv == SECSuccess ) { hasbase = PR_TRUE; } } else if ( catag ) { /* if the cert doesn't have the extensions, see if the issuer does */ rv = CERT_FindIssuerCertExtension(cert, catag, &urlitem); if ( rv != SECSuccess ) { goto loser; } rv = CERT_FindIssuerCertExtension(cert, SEC_OID_NS_CERT_EXT_BASE_URL, &baseitem); if ( rv == SECSuccess ) { hasbase = PR_TRUE; } } else { goto loser; } rv = SEC_QuickDERDecodeItem(arena, &urlstringitem, SEC_ASN1_GET(SEC_IA5StringTemplate), &urlitem); if ( rv != SECSuccess ) { goto loser; } if ( hasbase ) { rv = SEC_QuickDERDecodeItem(arena, &basestringitem, SEC_ASN1_GET(SEC_IA5StringTemplate), &baseitem); if ( rv != SECSuccess ) { goto loser; } } len = urlstringitem.len + ( hasbase ? basestringitem.len : 0 ) + 1; str = urlstring = (char *)PORT_Alloc(len); if ( urlstring == NULL ) { goto loser; } /* copy the URL base first */ if ( hasbase ) { /* if the urlstring has a : in it, then we assume it is an absolute * URL, and will not get the base string pre-pended */ for ( i = 0; i < urlstringitem.len; i++ ) { if ( urlstringitem.data[i] == ':' ) { goto nobase; } } PORT_Memcpy(str, basestringitem.data, basestringitem.len); str += basestringitem.len; } nobase: /* copy the rest (or all) of the URL */ PORT_Memcpy(str, urlstringitem.data, urlstringitem.len); str += urlstringitem.len; *str = '\0'; goto done; loser: if ( urlstring ) { PORT_Free(urlstring); } urlstring = NULL; done: if ( arena ) { PORT_FreeArena(arena, PR_FALSE); } if ( baseitem.data ) { PORT_Free(baseitem.data); } if ( urlitem.data ) { PORT_Free(urlitem.data); } return(urlstring); }
/* * smime_choose_cipher - choose a cipher that works for all the recipients * * "scert" - sender's certificate * "rcerts" - recipient's certificates */ static long smime_choose_cipher(CERTCertificate *scert, CERTCertificate **rcerts) { PLArenaPool *poolp; long cipher; long chosen_cipher; int *cipher_abilities; int *cipher_votes; int weak_mapi; int strong_mapi; int aes128_mapi; int aes256_mapi; int rcount, mapi, max, i; chosen_cipher = SMIME_RC2_CBC_40; /* the default, LCD */ weak_mapi = smime_mapi_by_cipher(chosen_cipher); aes128_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_128); aes256_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_256); poolp = PORT_NewArena (1024); /* XXX what is right value? */ if (poolp == NULL) goto done; cipher_abilities = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int)); cipher_votes = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int)); if (cipher_votes == NULL || cipher_abilities == NULL) goto done; /* Make triple-DES the strong cipher. */ strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168); /* walk all the recipient's certs */ for (rcount = 0; rcerts[rcount] != NULL; rcount++) { SECItem *profile; NSSSMIMECapability **caps; int pref; /* the first cipher that matches in the user's SMIME profile gets * "smime_cipher_map_count" votes; the next one gets "smime_cipher_map_count" - 1 * and so on. If every cipher matches, the last one gets 1 (one) vote */ pref = smime_cipher_map_count; /* find recipient's SMIME profile */ profile = CERT_FindSMimeProfile(rcerts[rcount]); if (profile != NULL && profile->data != NULL && profile->len > 0) { /* we have a profile (still DER-encoded) */ caps = NULL; /* decode it */ if (SEC_QuickDERDecodeItem(poolp, &caps, NSSSMIMECapabilitiesTemplate, profile) == SECSuccess && caps != NULL) { /* walk the SMIME capabilities for this recipient */ for (i = 0; caps[i] != NULL; i++) { cipher = nss_SMIME_FindCipherForSMIMECap(caps[i]); mapi = smime_mapi_by_cipher(cipher); if (mapi >= 0) { /* found the cipher */ cipher_abilities[mapi]++; cipher_votes[mapi] += pref; --pref; } } } } else { /* no profile found - so we can only assume that the user can do * the mandatory algorithms which are RC2-40 (weak crypto) and * 3DES (strong crypto), unless the user has an elliptic curve * key. For elliptic curve keys, RFC 5753 mandates support * for AES 128 CBC. */ SECKEYPublicKey *key; unsigned int pklen_bits; KeyType key_type; /* * if recipient's public key length is > 512, vote for a strong cipher * please not that the side effect of this is that if only one recipient * has an export-level public key, the strong cipher is disabled. * * XXX This is probably only good for RSA keys. What I would * really like is a function to just say; Is the public key in * this cert an export-length key? Then I would not have to * know things like the value 512, or the kind of key, or what * a subjectPublicKeyInfo is, etc. */ key = CERT_ExtractPublicKey(rcerts[rcount]); pklen_bits = 0; key_type = nullKey; if (key != NULL) { pklen_bits = SECKEY_PublicKeyStrengthInBits (key); key_type = SECKEY_GetPublicKeyType(key); SECKEY_DestroyPublicKey (key); key = NULL; } if (key_type == ecKey) { /* While RFC 5753 mandates support for AES-128 CBC, should use * AES 256 if user's key provides more than 128 bits of * security strength so that symmetric key is not weak link. */ /* RC2-40 is not compatible with elliptic curve keys. */ chosen_cipher = SMIME_DES_EDE3_168; if (pklen_bits > 256) { cipher_abilities[aes256_mapi]++; cipher_votes[aes256_mapi] += pref; pref--; } cipher_abilities[aes128_mapi]++; cipher_votes[aes128_mapi] += pref; pref--; cipher_abilities[strong_mapi]++; cipher_votes[strong_mapi] += pref; pref--; } else { if (pklen_bits > 512) { /* cast votes for the strong algorithm */ cipher_abilities[strong_mapi]++; cipher_votes[strong_mapi] += pref; pref--; } /* always cast (possibly less) votes for the weak algorithm */ cipher_abilities[weak_mapi]++; cipher_votes[weak_mapi] += pref; } } if (profile != NULL) SECITEM_FreeItem(profile, PR_TRUE); } /* find cipher that is agreeable by all recipients and that has the most votes */ max = 0; for (mapi = 0; mapi < smime_cipher_map_count; mapi++) { /* if not all of the recipients can do this, forget it */ if (cipher_abilities[mapi] != rcount) continue; /* if cipher is not enabled or not allowed by policy, forget it */ if (!smime_cipher_map[mapi].enabled || !smime_cipher_map[mapi].allowed) continue; /* now see if this one has more votes than the last best one */ if (cipher_votes[mapi] >= max) { /* if equal number of votes, prefer the ones further down in the list */ /* with the expectation that these are higher rated ciphers */ chosen_cipher = smime_cipher_map[mapi].cipher; max = cipher_votes[mapi]; } } /* if no common cipher was found, chosen_cipher stays at the default */ done: if (poolp != NULL) PORT_FreeArena (poolp, PR_FALSE); return chosen_cipher; }
SECStatus SGN_End(SGNContext *cx, SECItem *result) { unsigned char digest[HASH_LENGTH_MAX]; unsigned part1; int signatureLen; SECStatus rv; SECItem digder, sigitem; PLArenaPool *arena = 0; SECKEYPrivateKey *privKey = cx->key; SGNDigestInfo *di = 0; result->data = 0; digder.data = 0; sigitem.data = 0; /* Finish up digest function */ if (cx->hashcx == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest)); if (privKey->keyType == rsaKey && cx->signalg != SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { rv = SECFailure; goto loser; } /* Construct digest info */ di = SGN_CreateDigestInfo(cx->hashalg, digest, part1); if (!di) { rv = SECFailure; goto loser; } /* Der encode the digest as a DigestInfo */ rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di); if (rv != SECSuccess) { goto loser; } } else { digder.data = digest; digder.len = part1; } /* ** Encrypt signature after constructing appropriate PKCS#1 signature ** block */ signatureLen = PK11_SignatureLen(privKey); if (signatureLen <= 0) { PORT_SetError(SEC_ERROR_INVALID_KEY); rv = SECFailure; goto loser; } sigitem.len = signatureLen; sigitem.data = (unsigned char *)PORT_Alloc(signatureLen); if (sigitem.data == NULL) { rv = SECFailure; goto loser; } if (cx->signalg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { CK_RSA_PKCS_PSS_PARAMS mech; SECItem mechItem = { siBuffer, (unsigned char *)&mech, sizeof(mech) }; PORT_Memset(&mech, 0, sizeof(mech)); if (cx->params && cx->params->data) { SECKEYRSAPSSParams params; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { rv = SECFailure; goto loser; } PORT_Memset(¶ms, 0, sizeof(params)); rv = SEC_QuickDERDecodeItem(arena, ¶ms, SECKEY_RSAPSSParamsTemplate, cx->params); if (rv != SECSuccess) { goto loser; } rv = sec_RSAPSSParamsToMechanism(&mech, ¶ms); if (rv != SECSuccess) { goto loser; } } else { mech.hashAlg = CKM_SHA_1; mech.mgf = CKG_MGF1_SHA1; mech.sLen = digder.len; } rv = PK11_SignWithMechanism(privKey, CKM_RSA_PKCS_PSS, &mechItem, &sigitem, &digder); if (rv != SECSuccess) { goto loser; } } else { rv = PK11_Sign(privKey, &sigitem, &digder); if (rv != SECSuccess) { goto loser; } } if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) || (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */ rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); if (rv != SECSuccess) goto loser; SECITEM_FreeItem(&sigitem, PR_FALSE); } else { result->len = sigitem.len; result->data = sigitem.data; } loser: if (rv != SECSuccess) { SECITEM_FreeItem(&sigitem, PR_FALSE); } SGN_DestroyDigestInfo(di); if (arena != NULL) { PORT_FreeArena(arena, PR_FALSE); } return rv; }
static SECItem * sec_CreateRSAPSSParameters(PLArenaPool *arena, SECItem *result, SECOidTag hashAlgTag, const SECItem *params, const SECKEYPrivateKey *key) { SECKEYRSAPSSParams pssParams; int modBytes, hashLength; unsigned long saltLength; PRBool defaultSHA1 = PR_FALSE; SECStatus rv; if (key->keyType != rsaKey && key->keyType != rsaPssKey) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } PORT_Memset(&pssParams, 0, sizeof(pssParams)); if (params && params->data) { /* The parameters field should either be empty or contain * valid RSA-PSS parameters */ PORT_Assert(!(params->len == 2 && params->data[0] == SEC_ASN1_NULL && params->data[1] == 0)); rv = SEC_QuickDERDecodeItem(arena, &pssParams, SECKEY_RSAPSSParamsTemplate, params); if (rv != SECSuccess) { return NULL; } defaultSHA1 = PR_TRUE; } if (pssParams.trailerField.data) { unsigned long trailerField; rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.trailerField, &trailerField); if (rv != SECSuccess) { return NULL; } if (trailerField != 1) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } } modBytes = PK11_GetPrivateModulusLen((SECKEYPrivateKey *)key); /* Determine the hash algorithm to use, based on hashAlgTag and * pssParams.hashAlg; there are four cases */ if (hashAlgTag != SEC_OID_UNKNOWN) { SECOidTag tag = SEC_OID_UNKNOWN; if (pssParams.hashAlg) { tag = SECOID_GetAlgorithmTag(pssParams.hashAlg); } else if (defaultSHA1) { tag = SEC_OID_SHA1; } if (tag != SEC_OID_UNKNOWN && tag != hashAlgTag) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } } else if (hashAlgTag == SEC_OID_UNKNOWN) { if (pssParams.hashAlg) { hashAlgTag = SECOID_GetAlgorithmTag(pssParams.hashAlg); } else if (defaultSHA1) { hashAlgTag = SEC_OID_SHA1; } else { /* Find a suitable hash algorithm based on the NIST recommendation */ if (modBytes <= 384) { /* 128, in NIST 800-57, Part 1 */ hashAlgTag = SEC_OID_SHA256; } else if (modBytes <= 960) { /* 192, NIST 800-57, Part 1 */ hashAlgTag = SEC_OID_SHA384; } else { hashAlgTag = SEC_OID_SHA512; } } } if (hashAlgTag != SEC_OID_SHA1 && hashAlgTag != SEC_OID_SHA224 && hashAlgTag != SEC_OID_SHA256 && hashAlgTag != SEC_OID_SHA384 && hashAlgTag != SEC_OID_SHA512) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } /* Now that the hash algorithm is decided, check if it matches the * existing parameters if any */ if (pssParams.maskAlg) { SECAlgorithmID maskHashAlg; if (SECOID_GetAlgorithmTag(pssParams.maskAlg) != SEC_OID_PKCS1_MGF1) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } if (pssParams.maskAlg->parameters.data == NULL) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } PORT_Memset(&maskHashAlg, 0, sizeof(maskHashAlg)); rv = SEC_QuickDERDecodeItem(arena, &maskHashAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), &pssParams.maskAlg->parameters); if (rv != SECSuccess) { return NULL; } /* Following the recommendation in RFC 4055, assume the hash * algorithm identical to pssParam.hashAlg */ if (SECOID_GetAlgorithmTag(&maskHashAlg) != hashAlgTag) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } } else if (defaultSHA1) { if (hashAlgTag != SEC_OID_SHA1) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } } hashLength = HASH_ResultLenByOidTag(hashAlgTag); if (pssParams.saltLength.data) { rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.saltLength, &saltLength); if (rv != SECSuccess) { return NULL; } /* The specified salt length is too long */ if (saltLength > modBytes - hashLength - 2) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } } else if (defaultSHA1) { saltLength = 20; } /* Fill in the parameters */ if (pssParams.hashAlg) { if (hashAlgTag == SEC_OID_SHA1) { /* Omit hashAlg if the the algorithm is SHA-1 (default) */ pssParams.hashAlg = NULL; } } else { if (hashAlgTag != SEC_OID_SHA1) { pssParams.hashAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID)); if (!pssParams.hashAlg) { return NULL; } rv = SECOID_SetAlgorithmID(arena, pssParams.hashAlg, hashAlgTag, NULL); if (rv != SECSuccess) { return NULL; } } } if (pssParams.maskAlg) { if (hashAlgTag == SEC_OID_SHA1) { /* Omit maskAlg if the the algorithm is SHA-1 (default) */ pssParams.maskAlg = NULL; } } else { if (hashAlgTag != SEC_OID_SHA1) { SECItem *hashAlgItem; PORT_Assert(pssParams.hashAlg != NULL); hashAlgItem = SEC_ASN1EncodeItem(arena, NULL, pssParams.hashAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate)); if (!hashAlgItem) { return NULL; } pssParams.maskAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID)); if (!pssParams.maskAlg) { return NULL; } rv = SECOID_SetAlgorithmID(arena, pssParams.maskAlg, SEC_OID_PKCS1_MGF1, hashAlgItem); if (rv != SECSuccess) { return NULL; } } } if (pssParams.saltLength.data) { if (saltLength == 20) { /* Omit the salt length if it is the default */ pssParams.saltLength.data = NULL; } } else { /* Find a suitable length from the hash algorithm and modulus bits */ saltLength = PR_MIN(hashLength, modBytes - hashLength - 2); if (saltLength != 20 && !SEC_ASN1EncodeInteger(arena, &pssParams.saltLength, saltLength)) { return NULL; } } if (pssParams.trailerField.data) { /* Omit trailerField if the value is 1 (default) */ pssParams.trailerField.data = NULL; } return SEC_ASN1EncodeItem(arena, result, &pssParams, SECKEY_RSAPSSParamsTemplate); }
NS_IMETHODIMP nsDataSignatureVerifier::VerifyData(const nsACString & aData, const nsACString & aSignature, const nsACString & aPublicKey, bool *_retval) { // Allocate an arena to handle the majority of the allocations PRArenaPool *arena; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) return NS_ERROR_OUT_OF_MEMORY; // Base 64 decode the key SECItem keyItem; PORT_Memset(&keyItem, 0, sizeof(SECItem)); if (!NSSBase64_DecodeBuffer(arena, &keyItem, nsPromiseFlatCString(aPublicKey).get(), aPublicKey.Length())) { PORT_FreeArena(arena, false); return NS_ERROR_FAILURE; } // Extract the public key from the data CERTSubjectPublicKeyInfo *pki = SECKEY_DecodeDERSubjectPublicKeyInfo(&keyItem); if (!pki) { PORT_FreeArena(arena, false); return NS_ERROR_FAILURE; } SECKEYPublicKey *publicKey = SECKEY_ExtractPublicKey(pki); SECKEY_DestroySubjectPublicKeyInfo(pki); pki = nullptr; if (!publicKey) { PORT_FreeArena(arena, false); return NS_ERROR_FAILURE; } // Base 64 decode the signature SECItem signatureItem; PORT_Memset(&signatureItem, 0, sizeof(SECItem)); if (!NSSBase64_DecodeBuffer(arena, &signatureItem, nsPromiseFlatCString(aSignature).get(), aSignature.Length())) { SECKEY_DestroyPublicKey(publicKey); PORT_FreeArena(arena, false); return NS_ERROR_FAILURE; } // Decode the signature and algorithm CERTSignedData sigData; PORT_Memset(&sigData, 0, sizeof(CERTSignedData)); SECStatus ss = SEC_QuickDERDecodeItem(arena, &sigData, CERT_SignatureDataTemplate, &signatureItem); if (ss != SECSuccess) { SECKEY_DestroyPublicKey(publicKey); PORT_FreeArena(arena, false); return NS_ERROR_FAILURE; } // Perform the final verification DER_ConvertBitString(&(sigData.signature)); ss = VFY_VerifyDataWithAlgorithmID((const unsigned char*)nsPromiseFlatCString(aData).get(), aData.Length(), publicKey, &(sigData.signature), &(sigData.signatureAlgorithm), NULL, NULL); // Clean up remaining objects SECKEY_DestroyPublicKey(publicKey); PORT_FreeArena(arena, false); *_retval = (ss == SECSuccess); return NS_OK; }
CERTCrlDistributionPoints * CERT_DecodeCRLDistributionPoints (PLArenaPool *arena, SECItem *encodedValue) { CERTCrlDistributionPoints *value = NULL; CRLDistributionPoint **pointList, *point; SECStatus rv = SECSuccess; SECItem newEncodedValue; PORT_Assert (arena); do { value = PORT_ArenaZNew(arena, CERTCrlDistributionPoints); if (value == NULL) { rv = SECFailure; break; } /* copy the DER into the arena, since Quick DER returns data that points into the DER input, which may get freed by the caller */ rv = SECITEM_CopyItem(arena, &newEncodedValue, encodedValue); if (rv != SECSuccess) break; rv = SEC_QuickDERDecodeItem(arena, &value->distPoints, CERTCRLDistributionPointsTemplate, &newEncodedValue); if (rv != SECSuccess) break; pointList = value->distPoints; while (NULL != (point = *pointList)) { /* get the data if the distributionPointName is not omitted */ if (point->derDistPoint.data != NULL) { rv = SEC_QuickDERDecodeItem(arena, point, DistributionPointNameTemplate, &(point->derDistPoint)); if (rv != SECSuccess) break; switch (point->distPointType) { case generalName: point->distPoint.fullName = cert_DecodeGeneralNames(arena, point->derFullName); rv = point->distPoint.fullName ? SECSuccess : SECFailure; break; case relativeDistinguishedName: break; default: PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); rv = SECFailure; break; } /* end switch */ if (rv != SECSuccess) break; } /* end if */ /* Get the reason code if it's not omitted in the encoding */ if (point->bitsmap.data != NULL) { SECItem bitsmap = point->bitsmap; DER_ConvertBitString(&bitsmap); rv = SECITEM_CopyItem(arena, &point->reasons, &bitsmap); if (rv != SECSuccess) break; } /* Get the crl issuer name if it's not omitted in the encoding */ if (point->derCrlIssuer != NULL) { point->crlIssuer = cert_DecodeGeneralNames(arena, point->derCrlIssuer); if (!point->crlIssuer) break; } ++pointList; } /* end while points remain */ } while (0); return (rv == SECSuccess ? value : NULL); }
/* * check the consistancy and initialize a Public Key Object */ static CK_RV lg_createPublicKeyObject(SDB *sdb, CK_KEY_TYPE key_type, CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) { CK_ATTRIBUTE_TYPE pubKeyAttr = CKA_VALUE; CK_RV crv = CKR_OK; NSSLOWKEYPrivateKey *priv; SECItem pubKeySpace = { siBuffer, NULL, 0 }; SECItem *pubKey; #ifndef NSS_DISABLE_ECC SECItem pubKey2Space = { siBuffer, NULL, 0 }; PLArenaPool *arena = NULL; #endif /* NSS_DISABLE_ECC */ NSSLOWKEYDBHandle *keyHandle = NULL; switch (key_type) { case CKK_RSA: pubKeyAttr = CKA_MODULUS; break; #ifndef NSS_DISABLE_ECC case CKK_EC: pubKeyAttr = CKA_EC_POINT; break; #endif /* NSS_DISABLE_ECC */ case CKK_DSA: case CKK_DH: break; default: return CKR_ATTRIBUTE_VALUE_INVALID; } pubKey = &pubKeySpace; crv = lg_Attribute2SSecItem(NULL, pubKeyAttr, templ, count, pubKey); if (crv != CKR_OK) return crv; #ifndef NSS_DISABLE_ECC if (key_type == CKK_EC) { SECStatus rv; /* * for ECC, use the decoded key first. */ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { crv = CKR_HOST_MEMORY; goto done; } rv = SEC_QuickDERDecodeItem(arena, &pubKey2Space, SEC_ASN1_GET(SEC_OctetStringTemplate), pubKey); if (rv != SECSuccess) { /* decode didn't work, just try the pubKey */ PORT_FreeArena(arena, PR_FALSE); arena = NULL; } else { /* try the decoded pub key first */ pubKey = &pubKey2Space; } } #endif /* NSS_DISABLE_ECC */ PORT_Assert(pubKey->data); if (pubKey->data == NULL) { crv = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } keyHandle = lg_getKeyDB(sdb); if (keyHandle == NULL) { crv = CKR_TOKEN_WRITE_PROTECTED; goto done; } if (keyHandle->version != 3) { unsigned char buf[SHA1_LENGTH]; SHA1_HashBuf(buf, pubKey->data, pubKey->len); PORT_Memcpy(pubKey->data, buf, sizeof(buf)); pubKey->len = sizeof(buf); } /* make sure the associated private key already exists */ /* only works if we are logged in */ priv = nsslowkey_FindKeyByPublicKey(keyHandle, pubKey, sdb /*password*/); #ifndef NSS_DISABLE_ECC if (priv == NULL && pubKey == &pubKey2Space) { /* no match on the decoded key, match the original pubkey */ pubKey = &pubKeySpace; priv = nsslowkey_FindKeyByPublicKey(keyHandle, pubKey, sdb /*password*/); } #endif if (priv == NULL) { /* the legacy database can only 'store' public keys which already * have their corresponding private keys in the database */ crv = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } lg_nsslowkey_DestroyPrivateKey(priv); crv = CKR_OK; *handle = lg_mkHandle(sdb, pubKey, LG_TOKEN_TYPE_PUB); done: PORT_Free(pubKeySpace.data); #ifndef NSS_DISABLE_ECC if (arena) PORT_FreeArena(arena, PR_FALSE); #endif return crv; }
static long smime_choose_cipher(CERTCertificate *scert, CERTCertificate **rcerts) { PLArenaPool *poolp; long chosen_cipher; int *cipher_abilities; int *cipher_votes; int strong_mapi; int rcount, mapi, max; if (smime_policy_bits == 0) { PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); return -1; } chosen_cipher = SMIME_RC2_CBC_40; /* the default, LCD */ poolp = PORT_NewArena(1024); /* XXX what is right value? */ if (poolp == NULL) goto done; cipher_abilities = (int *)PORT_ArenaZAlloc(poolp, smime_symmetric_count * sizeof(int)); if (cipher_abilities == NULL) goto done; cipher_votes = (int *)PORT_ArenaZAlloc(poolp, smime_symmetric_count * sizeof(int)); if (cipher_votes == NULL) goto done; /* * XXX Should have a #define somewhere which specifies default * strong cipher. (Or better, a way to configure.) */ /* Make triple-DES the strong cipher. */ strong_mapi = smime_mapi_by_cipher(SMIME_DES_EDE3_168); PORT_Assert(strong_mapi >= 0); for (rcount = 0; rcerts[rcount] != NULL; rcount++) { SECItem *profile; smime_capability **caps; int capi, pref; SECStatus dstat; pref = smime_symmetric_count; profile = CERT_FindSMimeProfile(rcerts[rcount]); if (profile != NULL && profile->data != NULL && profile->len > 0) { caps = NULL; dstat = SEC_QuickDERDecodeItem(poolp, &caps, smime_capabilities_template, profile); if (dstat == SECSuccess && caps != NULL) { for (capi = 0; caps[capi] != NULL; capi++) { smime_fill_capability(caps[capi]); mapi = smime_mapi_by_cipher(caps[capi]->cipher); if (mapi >= 0) { cipher_abilities[mapi]++; cipher_votes[mapi] += pref; --pref; } } } } else { SECKEYPublicKey *key; unsigned int pklen_bits; /* * XXX This is probably only good for RSA keys. What I would * really like is a function to just say; Is the public key in * this cert an export-length key? Then I would not have to * know things like the value 512, or the kind of key, or what * a subjectPublicKeyInfo is, etc. */ key = CERT_ExtractPublicKey(rcerts[rcount]); if (key != NULL) { pklen_bits = SECKEY_PublicKeyStrength(key) * 8; SECKEY_DestroyPublicKey(key); if (pklen_bits > 512) { cipher_abilities[strong_mapi]++; cipher_votes[strong_mapi] += pref; } } } if (profile != NULL) SECITEM_FreeItem(profile, PR_TRUE); } max = 0; for (mapi = 0; mapi < smime_symmetric_count; mapi++) { if (cipher_abilities[mapi] != rcount) continue; if (!smime_cipher_allowed(smime_cipher_maps[mapi].cipher)) continue; if (cipher_votes[mapi] > max) { chosen_cipher = smime_cipher_maps[mapi].cipher; max = cipher_votes[mapi]; } /* XXX else if a tie, let scert break it? */ } done: if (poolp != NULL) PORT_FreeArena(poolp, PR_FALSE); return chosen_cipher; }
/* find a URL extension in the cert */ char * CERT_FindCertURLExtension(CERTCertificate *cert, SECOidTag tag) { SECStatus rv; SECItem urlitem = {siBuffer,0}; SECItem urlstringitem = {siBuffer,0}; PLArenaPool *arena = NULL; char *urlstring = NULL; char *str; int len; if (!cert) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( ! arena ) { goto loser; } rv = cert_FindExtension(cert->extensions, tag, &urlitem); if ( rv != SECSuccess ) { goto loser; } rv = SEC_QuickDERDecodeItem(arena, &urlstringitem, SEC_ASN1_GET(SEC_IA5StringTemplate), &urlitem); if ( rv != SECSuccess ) { goto loser; } len = urlstringitem.len + 1; str = urlstring = (char *)PORT_Alloc(len); if ( urlstring == NULL ) { goto loser; } /* copy the URL */ PORT_Memcpy(str, urlstringitem.data, urlstringitem.len); str += urlstringitem.len; *str = '\0'; goto done; loser: if ( urlstring ) { PORT_Free(urlstring); } urlstring = NULL; done: if ( arena ) { PORT_FreeArena(arena, PR_FALSE); } if ( urlitem.data ) { PORT_Free(urlitem.data); } return(urlstring); }
SECStatus SEC_ReadCertSequence(SECItem *certsItem, CERTImportCertificateFunc f, void *arg) { SECStatus rv; SECItem **certs; int count; SECItem **rawCerts = NULL; PRArenaPool *arena; SEC_PKCS7ContentInfo *contentInfo = NULL; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { return SECFailure; } contentInfo = SEC_PKCS7DecodeItem(certsItem, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if ( contentInfo == NULL ) { goto loser; } if ( SEC_PKCS7ContentType (contentInfo) != SEC_OID_NS_TYPE_CERT_SEQUENCE ) { goto loser; } rv = SEC_QuickDERDecodeItem(arena, &rawCerts, SEC_CertSequenceTemplate, contentInfo->content.data); if (rv != SECSuccess) { goto loser; } certs = rawCerts; if ( certs ) { count = 0; while ( *certs ) { count++; certs++; } rv = (* f)(arg, rawCerts, count); } rv = SECSuccess; goto done; loser: rv = SECFailure; done: if ( contentInfo ) { SEC_PKCS7DestroyContentInfo(contentInfo); } if ( arena ) { PORT_FreeArena(arena, PR_FALSE); } return(rv); }