static SECComparison _NSSCPY_CERT_CompareAVA(const CERTAVA *a, const CERTAVA *b) { SECComparison rv; rv = SECITEM_CompareItem(&a->type, &b->type); if (SECEqual != rv) return rv; /* Attribute types don't match. */ /* Let's be optimistic. Maybe the values will just compare equal. */ rv = SECITEM_CompareItem(&a->value, &b->value); if (SECEqual == rv) return rv; /* values compared exactly. */ if (a->value.len && a->value.data && b->value.len && b->value.data) { /* Here, the values did not match. ** If the values had different encodings, convert them to the same ** encoding and compare that way. */ if (a->value.data[0] != b->value.data[0]) { /* encodings differ. Convert both to UTF-8 and compare. */ SECItem * aVal = CERT_DecodeAVAValue(&a->value); SECItem * bVal = CERT_DecodeAVAValue(&b->value); if (aVal && aVal->len && aVal->data && bVal && bVal->len && bVal->data) { rv = SECITEM_CompareItem(aVal, bVal); } SECITEM_FreeItem(aVal, PR_TRUE); SECITEM_FreeItem(bVal, PR_TRUE); } else if (a->value.data[0] == 0x13) { /* both are printable strings. */ /* printable strings */ rv = _NSSCPY_CERT_CompareDERPrintableStrings(&a->value, &b->value); } } return rv; }
SECComparison SECOID_CompareAlgorithmID(SECAlgorithmID *a, SECAlgorithmID *b) { SECComparison rv; rv = SECITEM_CompareItem(&a->algorithm, &b->algorithm); if (rv) return rv; rv = SECITEM_CompareItem(&a->parameters, &b->parameters); return rv; }
/* * FUNCTION: pkix_pl_Date_Comparator * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_Date_Comparator( PKIX_PL_Object *firstObject, PKIX_PL_Object *secondObject, PKIX_Int32 *pResult, void *plContext) { SECItem *firstTime = NULL; SECItem *secondTime = NULL; SECComparison cmpResult; PKIX_ENTER(DATE, "pkix_pl_Date_Comparator"); PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); PKIX_CHECK(pkix_CheckTypes (firstObject, secondObject, PKIX_DATE_TYPE, plContext), PKIX_ARGUMENTSNOTDATES); firstTime = &((PKIX_PL_Date *)firstObject)->nssTime; secondTime = &((PKIX_PL_Date *)secondObject)->nssTime; PKIX_DATE_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); cmpResult = SECITEM_CompareItem(firstTime, secondTime); *pResult = cmpResult; cleanup: PKIX_RETURN(DATE); }
/* * FUNCTION: pkix_pl_OID_Comparator * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_OID_Comparator( PKIX_PL_Object *firstObject, PKIX_PL_Object *secondObject, PKIX_Int32 *pRes, void *plContext) { PKIX_PL_OID *firstOID = NULL; PKIX_PL_OID *secondOID = NULL; PKIX_ENTER(OID, "pkix_pl_OID_Comparator"); PKIX_NULLCHECK_THREE(firstObject, secondObject, pRes); PKIX_CHECK(pkix_CheckTypes (firstObject, secondObject, PKIX_OID_TYPE, plContext), PKIX_ARGUMENTSNOTOIDS); firstOID = (PKIX_PL_OID*)firstObject; secondOID = (PKIX_PL_OID*)secondObject; *pRes = (PKIX_Int32)SECITEM_CompareItem(&firstOID->derOid, &secondOID->derOid); cleanup: PKIX_RETURN(OID); }
/** * * Check that the Peer certificate's issuer certificate matches the one found * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the * issuer check, so we provide comments that mimic the OpenSSL * X509_check_issued function (in x509v3/v3_purp.c) */ static SECStatus check_issuer_cert(PRFileDesc *sock, char *issuer_nickname) { CERTCertificate *cert,*cert_issuer,*issuer; SECStatus res=SECSuccess; void *proto_win = NULL; /* PRArenaPool *tmpArena = NULL; CERTAuthKeyID *authorityKeyID = NULL; SECITEM *caname = NULL; */ cert = SSL_PeerCertificate(sock); cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner); proto_win = SSL_RevealPinArg(sock); issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win); if((!cert_issuer) || (!issuer)) res = SECFailure; else if(SECITEM_CompareItem(&cert_issuer->derCert, &issuer->derCert)!=SECEqual) res = SECFailure; CERT_DestroyCertificate(cert); CERT_DestroyCertificate(issuer); CERT_DestroyCertificate(cert_issuer); return res; }
/* * FUNCTION: pkix_pl_CRL_Equals * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_CRL_Equals( PKIX_PL_Object *firstObject, PKIX_PL_Object *secondObject, PKIX_Boolean *pResult, void *plContext) { PKIX_PL_CRL *firstCrl = NULL; PKIX_PL_CRL *secondCrl = NULL; PKIX_UInt32 secondType; PKIX_ENTER(CRL, "pkix_pl_CRL_Equals"); PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); /* test that firstObject is a CRL */ PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CRL_TYPE, plContext), PKIX_FIRSTOBJECTNOTCRL); firstCrl = (PKIX_PL_CRL *)firstObject; secondCrl = (PKIX_PL_CRL *)secondObject; /* * Since we know firstObject is a CRL, if both references are * identical, they must be equal */ if (firstCrl == secondCrl) { *pResult = PKIX_TRUE; goto cleanup; } /* * If secondCrl isn't a CRL, we don't throw an error. * We simply return a Boolean result of FALSE */ *pResult = PKIX_FALSE; PKIX_CHECK(PKIX_PL_Object_GetType ((PKIX_PL_Object *)secondCrl, &secondType, plContext), PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); if (secondType != PKIX_CRL_TYPE) goto cleanup; /* Compare DER Bytes */ PKIX_NULLCHECK_TWO (firstCrl->nssSignedCrl, firstCrl->nssSignedCrl->derCrl); PKIX_NULLCHECK_TWO (secondCrl->nssSignedCrl, secondCrl->nssSignedCrl->derCrl); PKIX_CRL_DEBUG("\t\tCalling SECITEM_CompareItem on derCrl\n"); if (SECITEM_CompareItem(firstCrl->nssSignedCrl->derCrl, secondCrl->nssSignedCrl->derCrl) == SECEqual) { *pResult = PKIX_TRUE; } cleanup: PKIX_RETURN(CRL); }
/* * FUNCTION: pkix_pl_Date_Equals * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_Date_Equals( PKIX_PL_Object *firstObject, PKIX_PL_Object *secondObject, PKIX_Boolean *pResult, void *plContext) { /* note: pkix_pl_Date can only represent UTCTime,not GeneralizedTime */ SECItem *firstTime = NULL; SECItem *secondTime = NULL; PKIX_UInt32 secondType; SECComparison cmpResult; PKIX_ENTER(DATE, "pkix_pl_Date_Equals"); PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); /* test that firstObject is a Date */ PKIX_CHECK(pkix_CheckType(firstObject, PKIX_DATE_TYPE, plContext), PKIX_FIRSTOBJECTNOTDATE); /* * Since we know firstObject is a Date, if both references are * identical, they must be equal */ if (firstObject == secondObject){ *pResult = PKIX_TRUE; goto cleanup; } /* * If secondObject isn't a Date, we don't throw an error. * We simply return a Boolean result of FALSE */ *pResult = PKIX_FALSE; PKIX_CHECK(PKIX_PL_Object_GetType (secondObject, &secondType, plContext), PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); if (secondType != PKIX_DATE_TYPE) goto cleanup; firstTime = &((PKIX_PL_Date *)firstObject)->nssTime; secondTime = &((PKIX_PL_Date *)secondObject)->nssTime; PKIX_DATE_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); cmpResult = SECITEM_CompareItem(firstTime, secondTime); *pResult = (cmpResult == SECEqual); cleanup: PKIX_RETURN(DATE); }
SECComparison SGN_CompareDigestInfo(SGNDigestInfo *a, SGNDigestInfo *b) { SECComparison rv; /* Check signature algorithm's */ rv = SECOID_CompareAlgorithmID(&a->digestAlgorithm, &b->digestAlgorithm); if (rv) return rv; /* Compare signature block length's */ rv = SECITEM_CompareItem(&a->digest, &b->digest); return rv; }
/* SECItems a and b contain DER-encoded printable strings. */ static SECComparison _NSSCPY_CERT_CompareDERPrintableStrings(const SECItem *a, const SECItem *b) { SECComparison rv = SECLessThan; SECItem * aVal = CERT_DecodeAVAValue(a); SECItem * bVal = CERT_DecodeAVAValue(b); if (aVal && aVal->len && aVal->data && bVal && bVal->len && bVal->data) { _NSSCPY_canonicalize(aVal); _NSSCPY_canonicalize(bVal); rv = SECITEM_CompareItem(aVal, bVal); } SECITEM_FreeItem(aVal, PR_TRUE); SECITEM_FreeItem(bVal, PR_TRUE); return rv; }
static SECStatus get_blinding_params(RSAPrivateKey *key, mp_int *n, unsigned int modLen, mp_int *f, mp_int *g) { SECStatus rv = SECSuccess; mp_err err = MP_OKAY; int cmp; PRCList *el; struct RSABlindingParamsStr *rsabp = NULL; /* Init the list if neccessary (the init function is only called once!) */ if (blindingParamsList.lock == NULL) { if (PR_CallOnce(&coBPInit, init_blinding_params_list) != PR_SUCCESS) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } } /* Acquire the list lock */ PZ_Lock(blindingParamsList.lock); /* Walk the list looking for the private key */ for (el = PR_NEXT_LINK(&blindingParamsList.head); el != &blindingParamsList.head; el = PR_NEXT_LINK(el)) { rsabp = (struct RSABlindingParamsStr *)el; cmp = SECITEM_CompareItem(&rsabp->modulus, &key->modulus); if (cmp == 0) { /* Check the usage counter for the parameters */ if (--rsabp->counter <= 0) { /* Regenerate the blinding parameters */ CHECK_SEC_OK( generate_blinding_params(rsabp, key, n, modLen) ); } /* Return the parameters */ CHECK_MPI_OK( mp_copy(&rsabp->f, f) ); CHECK_MPI_OK( mp_copy(&rsabp->g, g) ); /* Now that the params are located, release the list lock. */ PZ_Unlock(blindingParamsList.lock); /* XXX when fails? */ return SECSuccess; } else if (cmp > 0) { /* The key is not in the list. Break to param creation. */ break; } } /* At this point, the key is not in the list. el should point to the ** list element that this key should be inserted before. NOTE: the list ** lock is still held, so there cannot be a race condition here. */ rsabp = (struct RSABlindingParamsStr *) PORT_ZAlloc(sizeof(struct RSABlindingParamsStr)); if (!rsabp) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto cleanup; } /* Initialize the list pointer for the element */ PR_INIT_CLIST(&rsabp->link); /* Initialize the blinding parameters ** This ties up the list lock while doing some heavy, element-specific ** operations, but we don't want to insert the element until it is valid, ** which requires computing the blinding params. If this proves costly, ** it could be done after the list lock is released, and then if it fails ** the lock would have to be reobtained and the invalid element removed. */ rv = init_blinding_params(rsabp, key, n, modLen); if (rv != SECSuccess) { PORT_ZFree(rsabp, sizeof(struct RSABlindingParamsStr)); goto cleanup; } /* Insert the new element into the list ** If inserting in the middle of the list, el points to the link ** to insert before. Otherwise, the link needs to be appended to ** the end of the list, which is the same as inserting before the ** head (since el would have looped back to the head). */ PR_INSERT_BEFORE(&rsabp->link, el); /* Return the parameters */ CHECK_MPI_OK( mp_copy(&rsabp->f, f) ); CHECK_MPI_OK( mp_copy(&rsabp->g, g) ); /* Release the list lock */ PZ_Unlock(blindingParamsList.lock); /* XXX when fails? */ return SECSuccess; cleanup: /* It is possible to reach this after the lock is already released. ** Ignore the error in that case. */ PZ_Unlock(blindingParamsList.lock); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return SECFailure; }
/* 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; }
CK_RV jpake_Round2(HASH_HashType hashType, CK_NSS_JPAKERound2Params * params, SFTKObject * sourceKey, SFTKObject * key) { CK_RV crv; PLArenaPool * arena; PQGParams pqg; SECItem signerID, x2, gx1, gx2; SFTKItemTemplate sourceAttrs[] = { { CKA_PRIME, &pqg.prime }, { CKA_SUBPRIME, &pqg.subPrime }, { CKA_BASE, &pqg.base }, { CKA_NSS_JPAKE_SIGNERID, &signerID }, { CKA_NSS_JPAKE_X2, &x2 }, { CKA_NSS_JPAKE_GX1, &gx1 }, { CKA_NSS_JPAKE_GX2, &gx2 }, }; SECItem x2s, gx3, gx4; const SFTKItemTemplate copiedAndGeneratedAttrs[] = { { CKA_NSS_JPAKE_SIGNERID, &signerID }, { CKA_PRIME, &pqg.prime }, { CKA_SUBPRIME, &pqg.subPrime }, { CKA_NSS_JPAKE_X2, &x2 }, { CKA_NSS_JPAKE_X2S, &x2s }, { CKA_NSS_JPAKE_GX1, &gx1 }, { CKA_NSS_JPAKE_GX2, &gx2 }, { CKA_NSS_JPAKE_GX3, &gx3 }, { CKA_NSS_JPAKE_GX4, &gx4 } }; SECItem peerID; PORT_Assert(params != NULL); PORT_Assert(sourceKey != NULL); PORT_Assert(key != NULL); arena = PORT_NewArena(NSS_SOFTOKEN_DEFAULT_CHUNKSIZE); if (arena == NULL) crv = CKR_HOST_MEMORY; /* TODO: check CKK_NSS_JPAKE_ROUND1 */ crv = sftk_MultipleAttribute2SecItem(arena, sourceKey, sourceAttrs, NUM_ELEM(sourceAttrs)); /* Get the peer's ID out of the template and sanity-check it. */ if (crv == CKR_OK) crv = sftk_Attribute2SecItem(arena, &peerID, key, CKA_NSS_JPAKE_PEERID); if (crv == CKR_OK && (peerID.data == NULL || peerID.len == 0)) crv = CKR_TEMPLATE_INCOMPLETE; if (crv == CKR_OK && SECITEM_CompareItem(&signerID, &peerID) == SECEqual) crv = CKR_TEMPLATE_INCONSISTENT; /* Verify zero-knowledge proofs for g^x3 and g^x4 */ if (crv == CKR_OK) crv = jpake_Verify(arena, &pqg, hashType, &signerID, peerID.data, peerID.len, ¶ms->gx3); if (crv == CKR_OK) crv = jpake_Verify(arena, &pqg, hashType, &signerID, peerID.data, peerID.len, ¶ms->gx4); /* Calculate the base and x2s for A=base^x2s */ if (crv == CKR_OK) { SECItem s; s.data = params->pSharedKey; s.len = params->ulSharedKeyLen; gx3.data = params->gx3.pGX; gx3.len = params->gx3.ulGXLen; gx4.data = params->gx4.pGX; gx4.len = params->gx4.ulGXLen; pqg.base.data = NULL; x2s.data = NULL; crv = jpake_mapStatus(JPAKE_Round2(arena, &pqg.prime, &pqg.subPrime, &gx1, &gx3, &gx4, &pqg.base, &x2, &s, &x2s), CKR_MECHANISM_PARAM_INVALID); } /* Generate A=base^x2s and its zero-knowledge proof. */ if (crv == CKR_OK) crv = jpake_Sign(arena, &pqg, hashType, &signerID, &x2s, ¶ms->A); /* Copy P and Q from the ROUND1 key to the ROUND2 key and save the values needed for the final key material derivation into CKA_VALUE. */ if (crv == CKR_OK) crv = sftk_forceAttribute(key, CKA_PRIME, pqg.prime.data, pqg.prime.len); if (crv == CKR_OK) crv = sftk_forceAttribute(key, CKA_SUBPRIME, pqg.subPrime.data, pqg.subPrime.len); if (crv == CKR_OK) { crv = jpake_MultipleSecItem2Attribute(key, copiedAndGeneratedAttrs, NUM_ELEM(copiedAndGeneratedAttrs)); } if (crv == CKR_OK) crv = jpake_enforceKeyType(key, CKK_NSS_JPAKE_ROUND2); PORT_FreeArena(arena, PR_TRUE); return crv; }
static SECStatus get_blinding_params(RSAPrivateKey *key, mp_int *n, unsigned int modLen, mp_int *f, mp_int *g) { RSABlindingParams *rsabp = NULL; blindingParams *bpUnlinked = NULL; blindingParams *bp, *prevbp = NULL; PRCList *el; SECStatus rv = SECSuccess; mp_err err = MP_OKAY; int cmp = -1; PRBool holdingLock = PR_FALSE; do { if (blindingParamsList.lock == NULL) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } /* Acquire the list lock */ PZ_Lock(blindingParamsList.lock); holdingLock = PR_TRUE; /* Walk the list looking for the private key */ for (el = PR_NEXT_LINK(&blindingParamsList.head); el != &blindingParamsList.head; el = PR_NEXT_LINK(el)) { rsabp = (RSABlindingParams *)el; cmp = SECITEM_CompareItem(&rsabp->modulus, &key->modulus); if (cmp >= 0) { /* The key is found or not in the list. */ break; } } if (cmp) { /* At this point, the key is not in the list. el should point to ** the list element before which this key should be inserted. */ rsabp = PORT_ZNew(RSABlindingParams); if (!rsabp) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto cleanup; } rv = init_blinding_params(rsabp, key, n, modLen); if (rv != SECSuccess) { PORT_ZFree(rsabp, sizeof(RSABlindingParams)); goto cleanup; } /* Insert the new element into the list ** If inserting in the middle of the list, el points to the link ** to insert before. Otherwise, the link needs to be appended to ** the end of the list, which is the same as inserting before the ** head (since el would have looped back to the head). */ PR_INSERT_BEFORE(&rsabp->link, el); } /* We've found (or created) the RSAblindingParams struct for this key. * Now, search its list of ready blinding params for a usable one. */ while (0 != (bp = rsabp->bp)) { if (--(bp->counter) > 0) { /* Found a match and there are still remaining uses left */ /* Return the parameters */ CHECK_MPI_OK( mp_copy(&bp->f, f) ); CHECK_MPI_OK( mp_copy(&bp->g, g) ); PZ_Unlock(blindingParamsList.lock); return SECSuccess; } /* exhausted this one, give its values to caller, and * then retire it. */ mp_exch(&bp->f, f); mp_exch(&bp->g, g); mp_clear( &bp->f ); mp_clear( &bp->g ); bp->counter = 0; /* Move to free list */ rsabp->bp = bp->next; bp->next = rsabp->free; rsabp->free = bp; /* In case there're threads waiting for new blinding * value - notify 1 thread the value is ready */ if (blindingParamsList.waitCount > 0) { PR_NotifyCondVar( blindingParamsList.cVar ); blindingParamsList.waitCount--; } PZ_Unlock(blindingParamsList.lock); return SECSuccess; } /* We did not find a usable set of blinding params. Can we make one? */ /* Find a free bp struct. */ prevbp = NULL; if ((bp = rsabp->free) != NULL) { /* unlink this bp */ rsabp->free = bp->next; bp->next = NULL; bpUnlinked = bp; /* In case we fail */ PZ_Unlock(blindingParamsList.lock); holdingLock = PR_FALSE; /* generate blinding parameter values for the current thread */ CHECK_SEC_OK( generate_blinding_params(key, f, g, n, modLen ) ); /* put the blinding parameter values into cache */ CHECK_MPI_OK( mp_init( &bp->f) ); CHECK_MPI_OK( mp_init( &bp->g) ); CHECK_MPI_OK( mp_copy( f, &bp->f) ); CHECK_MPI_OK( mp_copy( g, &bp->g) ); /* Put this at head of queue of usable params. */ PZ_Lock(blindingParamsList.lock); holdingLock = PR_TRUE; /* initialize RSABlindingParamsStr */ bp->counter = RSA_BLINDING_PARAMS_MAX_REUSE; bp->next = rsabp->bp; rsabp->bp = bp; bpUnlinked = NULL; /* In case there're threads waiting for new blinding value * just notify them the value is ready */ if (blindingParamsList.waitCount > 0) { PR_NotifyAllCondVar( blindingParamsList.cVar ); blindingParamsList.waitCount = 0; } PZ_Unlock(blindingParamsList.lock); return SECSuccess; } /* Here, there are no usable blinding parameters available, * and no free bp blocks, presumably because they're all * actively having parameters generated for them. * So, we need to wait here and not eat up CPU until some * change happens. */ blindingParamsList.waitCount++; PR_WaitCondVar( blindingParamsList.cVar, PR_INTERVAL_NO_TIMEOUT ); PZ_Unlock(blindingParamsList.lock); holdingLock = PR_FALSE; } while (1); cleanup: /* It is possible to reach this after the lock is already released. */ if (bpUnlinked) { if (!holdingLock) { PZ_Lock(blindingParamsList.lock); holdingLock = PR_TRUE; } bp = bpUnlinked; mp_clear( &bp->f ); mp_clear( &bp->g ); bp->counter = 0; /* Must put the unlinked bp back on the free list */ bp->next = rsabp->free; rsabp->free = bp; } if (holdingLock) { PZ_Unlock(blindingParamsList.lock); holdingLock = PR_FALSE; } if (err) { MP_TO_SEC_ERROR(err); } return SECFailure; }
/* * Look to see if any of the signers in the cert chain for "cert" are found * in the list of caNames. * Returns SECSuccess if so, SECFailure if not. */ SECStatus NSS_CmpCertChainWCANames(CERTCertificate *cert, CERTDistNames *caNames) { SECItem * caname; CERTCertificate * curcert; CERTCertificate * oldcert; PRInt32 contentlen; int j; int headerlen; int depth; SECStatus rv; SECItem issuerName; SECItem compatIssuerName; if (!cert || !caNames || !caNames->nnames || !caNames->names || !caNames->names->data) return SECFailure; depth=0; curcert = CERT_DupCertificate(cert); while( curcert ) { issuerName = curcert->derIssuer; /* compute an alternate issuer name for compatibility with 2.0 * enterprise server, which send the CA names without * the outer layer of DER header */ rv = DER_Lengths(&issuerName, &headerlen, (PRUint32 *)&contentlen); if ( rv == SECSuccess ) { compatIssuerName.data = &issuerName.data[headerlen]; compatIssuerName.len = issuerName.len - headerlen; } else { compatIssuerName.data = NULL; compatIssuerName.len = 0; } for (j = 0; j < caNames->nnames; j++) { caname = &caNames->names[j]; if (SECITEM_CompareItem(&issuerName, caname) == SECEqual) { rv = SECSuccess; CERT_DestroyCertificate(curcert); goto done; } else if (SECITEM_CompareItem(&compatIssuerName, caname) == SECEqual) { rv = SECSuccess; CERT_DestroyCertificate(curcert); goto done; } } if ( ( depth <= 20 ) && ( SECITEM_CompareItem(&curcert->derIssuer, &curcert->derSubject) != SECEqual ) ) { oldcert = curcert; curcert = CERT_FindCertByName(curcert->dbhandle, &curcert->derIssuer); CERT_DestroyCertificate(oldcert); depth++; } else { CERT_DestroyCertificate(curcert); curcert = NULL; } } rv = SECFailure; done: return rv; }
int handle_connection( PRFileDesc *tcp_sock, PRFileDesc *model_sock, int requestCert) { PRFileDesc *ssl_sock = NULL; PRFileDesc *local_file_fd = NULL; char *pBuf; /* unused space at end of buf */ const char *errString; PRStatus status; int bufRem; /* unused bytes at end of buf */ int bufDat; /* characters received in buf */ int newln = 0; /* # of consecutive newlns */ int firstTime = 1; int reqLen; int rv; int numIOVs; PRSocketOptionData opt; PRIOVec iovs[16]; char msgBuf[160]; char buf[10240]; char fileName[513]; char *getData = NULL; /* inplace conversion */ SECItem postData; PRBool isOcspRequest = PR_FALSE; PRBool isPost; postData.data = NULL; postData.len = 0; pBuf = buf; bufRem = sizeof buf; VLOG(("httpserv: handle_connection: starting")); opt.option = PR_SockOpt_Nonblocking; opt.value.non_blocking = PR_FALSE; PR_SetSocketOption(tcp_sock, &opt); VLOG(("httpserv: handle_connection: starting\n")); ssl_sock = tcp_sock; if (noDelay) { opt.option = PR_SockOpt_NoDelay; opt.value.no_delay = PR_TRUE; status = PR_SetSocketOption(ssl_sock, &opt); if (status != PR_SUCCESS) { errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)"); if (ssl_sock) { PR_Close(ssl_sock); } return SECFailure; } } while (1) { const char *post; const char *foundStr = NULL; const char *tmp = NULL; newln = 0; reqLen = 0; rv = PR_Read(ssl_sock, pBuf, bufRem - 1); if (rv == 0 || (rv < 0 && PR_END_OF_FILE_ERROR == PR_GetError())) { if (verbose) errWarn("HDX PR_Read hit EOF"); break; } if (rv < 0) { errWarn("HDX PR_Read"); goto cleanup; } /* NULL termination */ pBuf[rv] = 0; if (firstTime) { firstTime = 0; } pBuf += rv; bufRem -= rv; bufDat = pBuf - buf; /* Parse the input, starting at the beginning of the buffer. * Stop when we detect two consecutive \n's (or \r\n's) * as this signifies the end of the GET or POST portion. * The posted data follows. */ while (reqLen < bufDat && newln < 2) { int octet = buf[reqLen++]; if (octet == '\n') { newln++; } else if (octet != '\r') { newln = 0; } } /* came to the end of the buffer, or second newln * If we didn't get an empty line (CRLFCRLF) then keep on reading. */ if (newln < 2) continue; /* we're at the end of the HTTP request. * If the request is a POST, then there will be one more * line of data. * This parsing is a hack, but ok for SSL test purposes. */ post = PORT_Strstr(buf, "POST "); if (!post || *post != 'P') break; postData.data = (void *)(buf + reqLen); tmp = "content-length: "; foundStr = PL_strcasestr(buf, tmp); if (foundStr) { int expectedPostLen; int havePostLen; expectedPostLen = atoi(foundStr + strlen(tmp)); havePostLen = bufDat - reqLen; if (havePostLen >= expectedPostLen) { postData.len = expectedPostLen; break; } } else { /* use legacy hack */ /* It's a post, so look for the next and final CR/LF. */ while (reqLen < bufDat && newln < 3) { int octet = buf[reqLen++]; if (octet == '\n') { newln++; } } if (newln == 3) break; } } /* read loop */ bufDat = pBuf - buf; if (bufDat) do { /* just close if no data */ /* Have either (a) a complete get, (b) a complete post, (c) EOF */ if (reqLen > 0) { PRBool isGetOrPost = PR_FALSE; unsigned skipChars = 0; isPost = PR_FALSE; if (!strncmp(buf, getCmd, sizeof getCmd - 1)) { isGetOrPost = PR_TRUE; skipChars = 4; } else if (!strncmp(buf, "POST ", 5)) { isGetOrPost = PR_TRUE; isPost = PR_TRUE; skipChars = 5; } if (isGetOrPost) { char *fnBegin = buf; char *fnEnd; char *fnstart = NULL; PRFileInfo info; fnBegin += skipChars; fnEnd = strpbrk(fnBegin, " \r\n"); if (fnEnd) { int fnLen = fnEnd - fnBegin; if (fnLen < sizeof fileName) { strncpy(fileName, fnBegin, fnLen); fileName[fnLen] = 0; /* null terminate */ fnstart = fileName; /* strip initial / because our root is the current directory*/ while (*fnstart && *fnstart == '/') ++fnstart; } } if (fnstart) { if (!strncmp(fnstart, "ocsp", 4)) { if (isPost) { if (postData.data) { isOcspRequest = PR_TRUE; } } else { if (!strncmp(fnstart, "ocsp/", 5)) { isOcspRequest = PR_TRUE; getData = fnstart + 5; } } } else { /* try to open the file named. * If successful, then write it to the client. */ status = PR_GetFileInfo(fnstart, &info); if (status == PR_SUCCESS && info.type == PR_FILE_FILE && info.size >= 0) { local_file_fd = PR_Open(fnstart, PR_RDONLY, 0); } } } } } numIOVs = 0; iovs[numIOVs].iov_base = (char *)outHeader; iovs[numIOVs].iov_len = (sizeof(outHeader)) - 1; numIOVs++; if (isOcspRequest && caRevoInfos) { CERTOCSPRequest *request = NULL; PRBool failThisRequest = PR_FALSE; PLArenaPool *arena = NULL; if (ocspMethodsAllowed == ocspGetOnly && postData.len) { failThisRequest = PR_TRUE; } else if (ocspMethodsAllowed == ocspPostOnly && getData) { failThisRequest = PR_TRUE; } else if (ocspMethodsAllowed == ocspRandomGetFailure && getData) { if (!(rand() % 2)) { failThisRequest = PR_TRUE; } } if (failThisRequest) { PR_Write(ssl_sock, outBadRequestHeader, strlen(outBadRequestHeader)); break; } /* get is base64, post is binary. * If we have base64, convert into the (empty) postData array. */ if (getData) { if (urldecode_base64chars_inplace(getData) == SECSuccess) { /* The code below can handle a NULL arena */ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); NSSBase64_DecodeBuffer(arena, &postData, getData, strlen(getData)); } } if (postData.len) { request = CERT_DecodeOCSPRequest(&postData); } if (arena) { PORT_FreeArena(arena, PR_FALSE); } if (!request || !request->tbsRequest || !request->tbsRequest->requestList || !request->tbsRequest->requestList[0]) { PORT_Sprintf(msgBuf, "Cannot decode OCSP request.\r\n"); iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } else { /* TODO: support more than one request entry */ CERTOCSPCertID *reqid = request->tbsRequest->requestList[0]->reqCert; const caRevoInfo *revoInfo = NULL; PRBool unknown = PR_FALSE; PRBool revoked = PR_FALSE; PRTime nextUpdate = 0; PRTime revoDate = 0; PRCList *caRevoIter; caRevoIter = &caRevoInfos->link; do { CERTOCSPCertID *caid; revoInfo = (caRevoInfo *)caRevoIter; caid = revoInfo->id; if (SECOID_CompareAlgorithmID(&reqid->hashAlgorithm, &caid->hashAlgorithm) == SECEqual && SECITEM_CompareItem(&reqid->issuerNameHash, &caid->issuerNameHash) == SECEqual && SECITEM_CompareItem(&reqid->issuerKeyHash, &caid->issuerKeyHash) == SECEqual) { break; } revoInfo = NULL; caRevoIter = PR_NEXT_LINK(caRevoIter); } while (caRevoIter != &caRevoInfos->link); if (!revoInfo) { unknown = PR_TRUE; revoInfo = caRevoInfos; } else { CERTCrl *crl = &revoInfo->crl->crl; CERTCrlEntry *entry = NULL; DER_DecodeTimeChoice(&nextUpdate, &crl->nextUpdate); if (crl->entries) { int iv = 0; /* assign, not compare */ while ((entry = crl->entries[iv++])) { if (SECITEM_CompareItem(&reqid->serialNumber, &entry->serialNumber) == SECEqual) { break; } } } if (entry) { /* revoked status response */ revoked = PR_TRUE; DER_DecodeTimeChoice(&revoDate, &entry->revocationDate); } else { /* else good status response */ if (!isPost && ocspMethodsAllowed == ocspGetUnknown) { unknown = PR_TRUE; nextUpdate = PR_Now() + (PRTime)60 * 60 * 24 * PR_USEC_PER_SEC; /*tomorrow*/ revoDate = PR_Now() - (PRTime)60 * 60 * 24 * PR_USEC_PER_SEC; /*yesterday*/ } } } { PRTime now = PR_Now(); PLArenaPool *arena = NULL; CERTOCSPSingleResponse *sr; CERTOCSPSingleResponse **singleResponses; SECItem *ocspResponse; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (unknown) { sr = CERT_CreateOCSPSingleResponseUnknown(arena, reqid, now, &nextUpdate); } else if (revoked) { sr = CERT_CreateOCSPSingleResponseRevoked(arena, reqid, now, &nextUpdate, revoDate, NULL); } else { sr = CERT_CreateOCSPSingleResponseGood(arena, reqid, now, &nextUpdate); } /* meaning of value 2: one entry + one end marker */ singleResponses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse *, 2); singleResponses[0] = sr; singleResponses[1] = NULL; ocspResponse = CERT_CreateEncodedOCSPSuccessResponse(arena, revoInfo->cert, ocspResponderID_byName, now, singleResponses, &pwdata); if (!ocspResponse) { PORT_Sprintf(msgBuf, "Failed to encode response\r\n"); iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } else { PR_Write(ssl_sock, outOcspHeader, strlen(outOcspHeader)); PR_Write(ssl_sock, ocspResponse->data, ocspResponse->len); PORT_FreeArena(arena, PR_FALSE); } } CERT_DestroyOCSPRequest(request); break; } } else if (local_file_fd) { PRInt32 bytes; int errLen; bytes = PR_TransmitFile(ssl_sock, local_file_fd, outHeader, sizeof outHeader - 1, PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); if (bytes >= 0) { bytes -= sizeof outHeader - 1; FPRINTF(stderr, "httpserv: PR_TransmitFile wrote %d bytes from %s\n", bytes, fileName); break; } errString = errWarn("PR_TransmitFile"); errLen = PORT_Strlen(errString); errLen = PR_MIN(errLen, sizeof msgBuf - 1); PORT_Memcpy(msgBuf, errString, errLen); msgBuf[errLen] = 0; iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } else if (reqLen <= 0) { /* hit eof */ PORT_Sprintf(msgBuf, "Get or Post incomplete after %d bytes.\r\n", bufDat); iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } else if (reqLen < bufDat) { PORT_Sprintf(msgBuf, "Discarded %d characters.\r\n", bufDat - reqLen); iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } if (reqLen > 0) { if (verbose > 1) fwrite(buf, 1, reqLen, stdout); /* display it */ iovs[numIOVs].iov_base = buf; iovs[numIOVs].iov_len = reqLen; numIOVs++; } rv = PR_Writev(ssl_sock, iovs, numIOVs, PR_INTERVAL_NO_TIMEOUT); if (rv < 0) { errWarn("PR_Writev"); break; } } while (0);
SECStatus ectest_ecdh_kat(ECDH_KAT *kat) { ECCurveName curve = kat->curve; ECParams ecParams = { 0 }; ECPrivateKey *ecPriv = NULL; SECItem theirKey = { siBuffer, NULL, 0 }; SECStatus rv = SECFailure; PLArenaPool *arena = NULL; SECItem seed = { siBuffer, NULL, 0 }; SECItem answer = { siBuffer, NULL, 0 }; SECItem answer2 = { siBuffer, NULL, 0 }; SECItem derived = { siBuffer, NULL, 0 }; SECItem ecEncodedParams = { siBuffer, NULL, 0 }; int i; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { return SECFailure; } rv = SECU_ecName2params(curve, &ecEncodedParams); if (rv != SECSuccess) { goto cleanup; } EC_FillParams(arena, &ecEncodedParams, &ecParams); if (kat->our_pubhex) { SECU_HexString2SECItem(arena, &answer, kat->our_pubhex); } SECU_HexString2SECItem(arena, &seed, kat->privhex); rv = EC_NewKeyFromSeed(&ecParams, &ecPriv, seed.data, seed.len); if (rv != SECSuccess) { rv = SECFailure; goto cleanup; } if (kat->our_pubhex) { if (SECITEM_CompareItem(&answer, &ecPriv->publicValue) != SECEqual) { rv = SECFailure; goto cleanup; } } SECU_HexString2SECItem(arena, &theirKey, kat->their_pubhex); SECU_HexString2SECItem(arena, &answer2, kat->common_key); rv = EC_ValidatePublicKey(&ecParams, &theirKey); if (rv != SECSuccess) { printf("EC_ValidatePublicKey failed\n"); goto cleanup; } for (i = 0; i < kat->iterations; ++i) { rv = ECDH_Derive(&theirKey, &ecParams, &ecPriv->privateValue, PR_TRUE, &derived); if (rv != SECSuccess) { rv = SECFailure; goto cleanup; } rv = SECITEM_CopyItem(ecParams.arena, &theirKey, &ecPriv->privateValue); if (rv != SECSuccess) { goto cleanup; } rv = SECITEM_CopyItem(ecParams.arena, &ecPriv->privateValue, &derived); if (rv != SECSuccess) { goto cleanup; } SECITEM_FreeItem(&derived, PR_FALSE); } if (SECITEM_CompareItem(&answer2, &ecPriv->privateValue) != SECEqual) { printf("expected: "); printBuf(&answer2); printf("derived: "); printBuf(&ecPriv->privateValue); rv = SECFailure; goto cleanup; } cleanup: SECITEM_FreeItem(&ecEncodedParams, PR_FALSE); PORT_FreeArena(arena, PR_FALSE); if (ecPriv) { PORT_FreeArena(ecPriv->ecParams.arena, PR_FALSE); } if (derived.data) { SECITEM_FreeItem(&derived, PR_FALSE); } return rv; }
/* search a certificate list for a nickname, a thumbprint, or both * within a certificate bag. if the certificate could not be * found or an error occurs, NULL is returned; */ static SEC_PKCS12CertAndCRL * sec_pkcs12_find_cert_in_certbag(SEC_PKCS12CertAndCRLBag *certbag, SECItem *nickname, SGNDigestInfo *thumbprint) { PRBool search_both = PR_FALSE, search_nickname = PR_FALSE; int i, j; if((certbag == NULL) || ((nickname == NULL) && (thumbprint == NULL))) { return NULL; } if(thumbprint && nickname) { search_both = PR_TRUE; } if(nickname) { search_nickname = PR_TRUE; } search_again: i = 0; while(certbag->certAndCRLs[i] != NULL) { SEC_PKCS12CertAndCRL *cert = certbag->certAndCRLs[i]; if(SECOID_FindOIDTag(&cert->BagID) == SEC_OID_PKCS12_X509_CERT_CRL_BAG) { /* check nicknames */ if(search_nickname) { if(SECITEM_CompareItem(nickname, &cert->nickname) == SECEqual) { return cert; } } else { /* check thumbprints */ SECItem **derCertList; /* get pointer to certificate list, does not need to * be freed since it is within the arena which will * be freed later. */ derCertList = SEC_PKCS7GetCertificateList(&cert->value.x509->certOrCRL); j = 0; if(derCertList != NULL) { while(derCertList[j] != NULL) { SECComparison eq; SGNDigestInfo *di; di = sec_pkcs12_compute_thumbprint(derCertList[j]); if(di) { eq = SGN_CompareDigestInfo(thumbprint, di); SGN_DestroyDigestInfo(di); if(eq == SECEqual) { /* copy the derCert for later reference */ cert->value.x509->derLeafCert = derCertList[j]; return cert; } } else { /* an error occurred */ return NULL; } j++; } } } } i++; } if(search_both) { search_both = PR_FALSE; search_nickname = PR_FALSE; goto search_again; } return NULL; }
/* * FUNCTION: pkix_pl_GeneralName_Equals * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_GeneralName_Equals( PKIX_PL_Object *firstObject, PKIX_PL_Object *secondObject, PKIX_Boolean *pResult, void *plContext) { PKIX_PL_GeneralName *firstName = NULL; PKIX_PL_GeneralName *secondName = NULL; PKIX_UInt32 secondType; PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Equals"); PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); /* test that firstObject is a GeneralName */ PKIX_CHECK(pkix_CheckType (firstObject, PKIX_GENERALNAME_TYPE, plContext), PKIX_FIRSTOBJECTNOTGENERALNAME); /* * Since we know firstObject is a GeneralName, if both references are * identical, they must be equal */ if (firstObject == secondObject){ *pResult = PKIX_TRUE; goto cleanup; } /* * If secondObject isn't a GeneralName, we don't throw an error. * We simply return a Boolean result of FALSE */ *pResult = PKIX_FALSE; PKIX_CHECK(PKIX_PL_Object_GetType (secondObject, &secondType, plContext), PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); if (secondType != PKIX_GENERALNAME_TYPE){ goto cleanup; } firstName = (PKIX_PL_GeneralName *)firstObject; secondName = (PKIX_PL_GeneralName *)secondObject; if (firstName->type != secondName->type){ goto cleanup; } switch (firstName->type) { case certRFC822Name: case certDNSName: case certX400Address: case certEDIPartyName: case certURI: case certIPAddress: PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); if (SECITEM_CompareItem(firstName->other, secondName->other) != SECEqual) { goto cleanup; } break; case certRegisterID: PKIX_CHECK(PKIX_PL_Object_Equals ((PKIX_PL_Object *)firstName->oid, (PKIX_PL_Object *)secondName->oid, pResult, plContext), PKIX_OIDEQUALSFAILED); goto cleanup; case certOtherName: PKIX_NULLCHECK_TWO(firstName->OthName, secondName->OthName); PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); if (SECITEM_CompareItem(&firstName->OthName->oid, &secondName->OthName->oid) != SECEqual || SECITEM_CompareItem(&firstName->OthName->name, &secondName->OthName->name) != SECEqual) { goto cleanup; } break; case certDirectoryName: PKIX_CHECK(PKIX_PL_Object_Equals ((PKIX_PL_Object *)firstName->directoryName, (PKIX_PL_Object *)secondName->directoryName, pResult, plContext), PKIX_X500NAMEEQUALSFAILED); goto cleanup; } *pResult = PKIX_TRUE; cleanup: PKIX_RETURN(GENERALNAME); }
/* search a key list for a nickname, a thumbprint, or both * within a key bag. if the key could not be * found or an error occurs, NULL is returned; */ static SEC_PKCS12PrivateKey * sec_pkcs12_find_key_in_keybag(SEC_PKCS12PrivateKeyBag *keybag, SECItem *nickname, SGNDigestInfo *thumbprint) { PRBool search_both = PR_FALSE, search_nickname = PR_FALSE; int i, j; if((keybag == NULL) || ((nickname == NULL) && (thumbprint == NULL))) { return NULL; } if(keybag->privateKeys == NULL) { return NULL; } if(thumbprint && nickname) { search_both = PR_TRUE; } if(nickname) { search_nickname = PR_TRUE; } search_again: i = 0; while(keybag->privateKeys[i] != NULL) { SEC_PKCS12PrivateKey *key = keybag->privateKeys[i]; /* check nicknames */ if(search_nickname) { if(SECITEM_CompareItem(nickname, &key->pvkData.nickname) == SECEqual) { return key; } } else { /* check digests */ SGNDigestInfo **assocCerts = key->pvkData.assocCerts; if((assocCerts == NULL) || (assocCerts[0] == NULL)) { return NULL; } j = 0; while(assocCerts[j] != NULL) { SECComparison eq; eq = SGN_CompareDigestInfo(thumbprint, assocCerts[j]); if(eq == SECEqual) { return key; } j++; } } i++; } if(search_both) { search_both = PR_FALSE; search_nickname = PR_FALSE; goto search_again; } return NULL; }