static void purple_aes_cipher_nss_cleanup(PurpleAESCipherNSSContext *context) { g_return_if_fail(context != NULL); if (context->enc_context != NULL) PK11_DestroyContext(context->enc_context, TRUE); if (context->sec_param != NULL) SECITEM_FreeItem(context->sec_param, TRUE); if (context->sym_key != NULL) PK11_FreeSymKey(context->sym_key); if (context->slot != NULL) PK11_FreeSlot(context->slot); memset(context, 0, sizeof(PurpleAESCipherNSSContext)); }
static void ssl_FreeCipherSpec(ssl3CipherSpec *spec) { SSL_TRC(10, ("%d: SSL[-]: Freeing %s spec %d. epoch=%d", SSL_GETPID(), SPEC_DIR(spec), spec, spec->epoch)); PR_REMOVE_LINK(&spec->link); /* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */ if (spec->cipherContext) { PK11_DestroyContext(spec->cipherContext, PR_TRUE); } PK11_FreeSymKey(spec->masterSecret); ssl_DestroyKeyMaterial(&spec->keyMaterial); PORT_ZFree(spec, sizeof(*spec)); }
/* * Free up a Cipher Context */ void PK11_DestroyContext(PK11Context *context, PRBool freeit) { pk11_CloseSession(context->slot, context->session, context->ownSession); /* initialize the critical fields of the context */ if (context->savedData != NULL) PORT_Free(context->savedData); if (context->key) PK11_FreeSymKey(context->key); if (context->param && context->param != &pk11_null_params) SECITEM_FreeItem(context->param, PR_TRUE); if (context->sessionLock) PZ_DestroyLock(context->sessionLock); PK11_FreeSlot(context->slot); if (freeit) PORT_Free(context); }
/* * DestroyPk11PinStore */ void DestroyPk11PinStore(Pk11PinStore *store) { if (store == 0) return; if (store->params) { SECITEM_ZfreeItem(store->params, PR_TRUE); } if (store->key) { PK11_FreeSymKey(store->key); } if (store->crypt) { memset(store->crypt, 0, store->length); free(store->crypt); } free(store); }
char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) { PK11SlotInfo *slot = NULL; PK11SymKey *pkey = NULL; PK11Context *context = NULL; unsigned char digest[20]; // Is there a way to tell how large the output is? unsigned int len; SECStatus s; SECItem keyItem, noParams; char *rv=NULL; keyItem.type = siBuffer; keyItem.data = (unsigned char*) k; keyItem.len = kl; noParams.type = siBuffer; noParams.data = NULL; noParams.len = 0; oauth_init_nss(); slot = PK11_GetInternalKeySlot(); if (!slot) goto looser; pkey = PK11_ImportSymKey(slot, CKM_SHA_1_HMAC, PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL); if (!pkey) goto looser; context = PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, CKA_SIGN, pkey, &noParams); if (!context) goto looser; s = PK11_DigestBegin(context); if (s != SECSuccess) goto looser; s = PK11_DigestOp(context, (unsigned char*) m, ml); if (s != SECSuccess) goto looser; s = PK11_DigestFinal(context, digest, &len, sizeof digest); if (s != SECSuccess) goto looser; rv=oauth_encode_base64(len, digest); looser: if (context) PK11_DestroyContext(context, PR_TRUE); if (pkey) PK11_FreeSymKey(pkey); if (slot) PK11_FreeSlot(slot); return rv; }
/* * NSS_CMSEncryptedData_Decode_BeforeData - find bulk key & set up decryption */ SECStatus NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd) { PK11SymKey *bulkkey = NULL; NSSCMSContentInfo *cinfo; SECAlgorithmID *bulkalg; SECStatus rv = SECFailure; cinfo = &(encd->contentInfo); bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo); if (encd->cmsg->decrypt_key_cb == NULL) /* no callback? no key../ */ goto loser; bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg); if (bulkkey == NULL) /* no success finding a bulk key */ goto loser; NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey); rv = NSS_CMSContentInfo_Private_Init(cinfo); if (rv != SECSuccess) { goto loser; } rv = SECFailure; cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg); if (cinfo->privateInfo->ciphcx == NULL) goto loser; /* error has been set by NSS_CMSCipherContext_StartDecrypt */ /* we are done with (this) bulkkey now. */ PK11_FreeSymKey(bulkkey); rv = SECSuccess; loser: return rv; }
/*********************************************************************** * * J S S _ P K 1 1 _ w r a p S y m K e y * Puts a Symmetric Key into a Java object. * (Does NOT perform a cryptographic "wrap" operation.) * symKey: will be stored in a Java wrapper. * Returns: a new PK11SymKey, or NULL if an exception occurred. */ jobject JSS_PK11_wrapSymKey(JNIEnv *env, PK11SymKey **symKey) { jclass keyClass; jmethodID constructor; jbyteArray ptrArray; jobject Key=NULL; PR_ASSERT(env!=NULL && symKey!=NULL && *symKey!=NULL); /* find the class */ keyClass = (*env)->FindClass(env, PK11SYMKEY_CLASS_NAME); if( keyClass == NULL ) { ASSERT_OUTOFMEM(env); goto finish; } /* find the constructor */ constructor = (*env)->GetMethodID(env, keyClass, PLAIN_CONSTRUCTOR, PK11SYMKEY_CONSTRUCTOR_SIG); if(constructor == NULL) { ASSERT_OUTOFMEM(env); goto finish; } /* convert the pointer to a byte array */ ptrArray = JSS_ptrToByteArray(env, (void*)*symKey); if( ptrArray == NULL ) { goto finish; } /* call the constructor */ Key = (*env)->NewObject(env, keyClass, constructor, ptrArray); finish: if(Key == NULL) { PK11_FreeSymKey(*symKey); } *symKey = NULL; return Key; }
/* * Create a context from a key. We really should make sure we aren't using * the same key in multiple session! */ PK11Context * PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey, SECItem *param) { PK11SymKey *newKey; PK11Context *context; /* if this slot doesn't support the mechanism, go to a slot that does */ newKey = pk11_ForceSlot(symKey, type, operation); if (newKey == NULL) { PK11_ReferenceSymKey(symKey); } else { symKey = newKey; } /* Context Adopts the symKey.... */ context = pk11_CreateNewContextInSlot(type, symKey->slot, operation, symKey, param); PK11_FreeSymKey(symKey); return context; }
void nsKeyObject::CleanUp() { switch (mKeyType) { case nsIKeyObject::SYM_KEY: PK11_FreeSymKey(mSymKey); break; case nsIKeyObject::PRIVATE_KEY: PK11_DeleteTokenPrivateKey(mPrivateKey, PR_TRUE /* force */); break; case nsIKeyObject::PUBLIC_KEY: PK11_DeleteTokenPublicKey(mPublicKey); break; default: // probably not initialized, do nothing break; } mKeyType = 0; }
/* * create a symetric key: * Slot is the slot to create the key in. * type is the mechanism type * owner is does this symKey structure own it's object handle (rare * that this is false). * needSession means the returned symKey will return with a valid session * allocated already. */ static PK11SymKey * pk11_CreateSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PRBool owner, PRBool needSession, void *wincx) { PK11SymKey *symKey = pk11_getKeyFromList(slot, needSession); if (symKey == NULL) { return NULL; } /* if needSession was specified, make sure we have a valid session. * callers which specify needSession as false should do their own * check of the session before returning the symKey */ if (needSession && symKey->session == CK_INVALID_SESSION) { PK11_FreeSymKey(symKey); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return NULL; } symKey->type = type; symKey->data.type = siBuffer; symKey->data.data = NULL; symKey->data.len = 0; symKey->owner = owner; symKey->objectID = CK_INVALID_HANDLE; symKey->slot = slot; symKey->series = slot->series; symKey->cx = wincx; symKey->size = 0; symKey->refCount = 1; symKey->origin = PK11_OriginNULL; symKey->parent = NULL; symKey->freeFunc = NULL; symKey->userData = NULL; PK11_ReferenceSlot(slot); return symKey; }
SECStatus ListKeys(PK11SlotInfo *slot, int *printLabel, void *pwd) { PK11SymKey *keyList; SECStatus rv = PK11_Authenticate(slot, PR_FALSE, pwd); if (rv != SECSuccess) { return rv;; } keyList = PK11_ListFixedKeysInSlot(slot, NULL, pwd); if (keyList) { if (*printLabel) { printf(" Name Len Strength Type Data\n"); *printLabel = 0; } printf("%s:\n",PK11_GetTokenName(slot)); } while (keyList) { PK11SymKey *freeKey = keyList; PrintKey(keyList); keyList = PK11_GetNextSymKey(keyList); PK11_FreeSymKey(freeKey); } return SECSuccess; }
/* * put together the various PK11_Create_Context calls used by different * parts of libsec. */ PK11Context * __PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, SECItem *param, void *wincx) { PK11SymKey *symKey = NULL; PK11Context *context = NULL; /* first get a slot */ if (slot == NULL) { slot = PK11_GetBestSlot(type, wincx); if (slot == NULL) { PORT_SetError(SEC_ERROR_NO_MODULE); goto loser; } } else { PK11_ReferenceSlot(slot); } /* now import the key */ symKey = PK11_ImportSymKey(slot, type, origin, operation, key, wincx); if (symKey == NULL) goto loser; context = PK11_CreateContextBySymKey(type, operation, symKey, param); loser: if (symKey) { PK11_FreeSymKey(symKey); } if (slot) { PK11_FreeSlot(slot); } return context; }
/* * NSS_CMSContentInfo_Destroy - destroy a CMS contentInfo and all of its sub-pieces. */ void NSS_CMSContentInfo_Destroy(NSSCMSContentInfo *cinfo) { SECOidTag kind; if (cinfo == NULL) { return; } kind = NSS_CMSContentInfo_GetContentTypeTag(cinfo); switch (kind) { case SEC_OID_PKCS7_ENVELOPED_DATA: NSS_CMSEnvelopedData_Destroy(cinfo->content.envelopedData); break; case SEC_OID_PKCS7_SIGNED_DATA: NSS_CMSSignedData_Destroy(cinfo->content.signedData); break; case SEC_OID_PKCS7_ENCRYPTED_DATA: NSS_CMSEncryptedData_Destroy(cinfo->content.encryptedData); break; case SEC_OID_PKCS7_DIGESTED_DATA: NSS_CMSDigestedData_Destroy(cinfo->content.digestedData); break; default: NSS_CMSGenericWrapperData_Destroy(kind, cinfo->content.genericData); /* XXX Anything else that needs to be "manually" freed/destroyed? */ break; } if (cinfo->privateInfo) { nss_cmsContentInfo_private_destroy(cinfo->privateInfo); cinfo->privateInfo = NULL; } if (cinfo->bulkkey) { PK11_FreeSymKey(cinfo->bulkkey); } }
char * crypto_decrypt (const char *cipher, int key_type, const guint8 *data, gsize data_len, const char *iv, const gsize iv_len, const char *key, const gsize key_len, gsize *out_len, GError **error) { char *output = NULL; int decrypted_len = 0; CK_MECHANISM_TYPE cipher_mech; PK11SlotInfo *slot = NULL; SECItem key_item; PK11SymKey *sym_key = NULL; SECItem *sec_param = NULL; PK11Context *ctx = NULL; SECStatus s; gboolean success = FALSE; unsigned int pad_len = 0, extra = 0; guint32 i, real_iv_len = 0; if (!crypto_init (error)) return NULL; if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) { cipher_mech = CKM_DES3_CBC_PAD; real_iv_len = 8; } else if (!strcmp (cipher, CIPHER_DES_CBC)) { cipher_mech = CKM_DES_CBC_PAD; real_iv_len = 8; } else if (!strcmp (cipher, CIPHER_AES_CBC)) { cipher_mech = CKM_AES_CBC_PAD; real_iv_len = 16; } else { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_UNKNOWN_CIPHER, _("Private key cipher '%s' was unknown."), cipher); return NULL; } if (iv_len < real_iv_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA, _("Invalid IV length (must be at least %d)."), real_iv_len); return NULL; } output = g_malloc0 (data_len); slot = PK11_GetBestSlot (cipher_mech, NULL); if (!slot) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_FAILED, _("Failed to initialize the decryption cipher slot.")); goto out; } key_item.data = (unsigned char *) key; key_item.len = key_len; sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_DECRYPT, &key_item, NULL); if (!sym_key) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to set symmetric key for decryption.")); goto out; } key_item.data = (unsigned char *) iv; key_item.len = real_iv_len; sec_param = PK11_ParamFromIV (cipher_mech, &key_item); if (!sec_param) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to set IV for decryption.")); goto out; } ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_DECRYPT, sym_key, sec_param); if (!ctx) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to initialize the decryption context.")); goto out; } s = PK11_CipherOp (ctx, (unsigned char *) output, &decrypted_len, data_len, data, data_len); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key: %d."), PORT_GetError ()); goto out; } if (decrypted_len > data_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key: decrypted data too large.")); goto out; } s = PK11_DigestFinal (ctx, (unsigned char *) (output + decrypted_len), &extra, data_len - decrypted_len); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to finalize decryption of the private key: %d."), PORT_GetError ()); goto out; } decrypted_len += extra; pad_len = data_len - decrypted_len; /* Check if the padding at the end of the decrypted data is valid */ if (pad_len == 0 || pad_len > real_iv_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key: unexpected padding length.")); goto out; } /* Validate tail padding; last byte is the padding size, and all pad bytes * should contain the padding size. */ for (i = pad_len; i > 0; i--) { if (output[data_len - i] != pad_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key.")); goto out; } } *out_len = decrypted_len; success = TRUE; out: if (ctx) PK11_DestroyContext (ctx, PR_TRUE); if (sym_key) PK11_FreeSymKey (sym_key); if (sec_param) SECITEM_FreeItem (sec_param, PR_TRUE); if (slot) PK11_FreeSlot (slot); if (!success) { if (output) { /* Don't expose key material */ memset (output, 0, data_len); g_free (output); output = NULL; } } return output; }
/* * pk11_getKeyFromList returns a symKey that has a session (if needSession * was specified), or explicitly does not have a session (if needSession * was not specified). */ static PK11SymKey * pk11_getKeyFromList(PK11SlotInfo *slot, PRBool needSession) { PK11SymKey *symKey = NULL; PZ_Lock(slot->freeListLock); /* own session list are symkeys with sessions that the symkey owns. * 'most' symkeys will own their own session. */ if (needSession) { if (slot->freeSymKeysWithSessionHead) { symKey = slot->freeSymKeysWithSessionHead; slot->freeSymKeysWithSessionHead = symKey->next; slot->keyCount--; } } /* if we don't need a symkey with its own session, or we couldn't find * one on the owner list, get one from the non-owner free list. */ if (!symKey) { if (slot->freeSymKeysHead) { symKey = slot->freeSymKeysHead; slot->freeSymKeysHead = symKey->next; slot->keyCount--; } } PZ_Unlock(slot->freeListLock); if (symKey) { symKey->next = NULL; if (!needSession) { return symKey; } /* if we are getting an owner key, make sure we have a valid session. * session could be invalid if the token has been removed or because * we got it from the non-owner free list */ if ((symKey->series != slot->series) || (symKey->session == CK_INVALID_SESSION)) { symKey->session = pk11_GetNewSession(slot, &symKey->sessionOwner); } PORT_Assert(symKey->session != CK_INVALID_SESSION); if (symKey->session != CK_INVALID_SESSION) return symKey; PK11_FreeSymKey(symKey); /* if we are here, we need a session, but couldn't get one, it's * unlikely we pk11_GetNewSession will succeed if we call it a second * time. */ return NULL; } symKey = PORT_New(PK11SymKey); if (symKey == NULL) { return NULL; } symKey->next = NULL; if (needSession) { symKey->session = pk11_GetNewSession(slot,&symKey->sessionOwner); PORT_Assert(symKey->session != CK_INVALID_SESSION); if (symKey->session == CK_INVALID_SESSION) { PK11_FreeSymKey(symKey); symKey = NULL; } } else { symKey->session = CK_INVALID_SESSION; } return symKey; }
/* * destroy a symetric key */ void PK11_FreeSymKey(PK11SymKey *symKey) { PK11SlotInfo *slot; PRBool freeit = PR_TRUE; if (PR_ATOMIC_DECREMENT(&symKey->refCount) == 0) { PK11SymKey *parent = symKey->parent; symKey->parent = NULL; if ((symKey->owner) && symKey->objectID != CK_INVALID_HANDLE) { pk11_EnterKeyMonitor(symKey); (void) PK11_GETTAB(symKey->slot)-> C_DestroyObject(symKey->session, symKey->objectID); pk11_ExitKeyMonitor(symKey); } if (symKey->data.data) { PORT_Memset(symKey->data.data, 0, symKey->data.len); PORT_Free(symKey->data.data); } /* free any existing data */ if (symKey->userData && symKey->freeFunc) { (*symKey->freeFunc)(symKey->userData); } slot = symKey->slot; PZ_Lock(slot->freeListLock); if (slot->keyCount < slot->maxKeyCount) { /* * freeSymkeysWithSessionHead contain a list of reusable * SymKey structures with valid sessions. * sessionOwner must be true. * session must be valid. * freeSymKeysHead contain a list of SymKey structures without * valid session. * session must be CK_INVALID_SESSION. * though sessionOwner is false, callers should not depend on * this fact. */ if (symKey->sessionOwner) { PORT_Assert (symKey->session != CK_INVALID_SESSION); symKey->next = slot->freeSymKeysWithSessionHead; slot->freeSymKeysWithSessionHead = symKey; } else { symKey->session = CK_INVALID_SESSION; symKey->next = slot->freeSymKeysHead; slot->freeSymKeysHead = symKey; } slot->keyCount++; symKey->slot = NULL; freeit = PR_FALSE; } PZ_Unlock(slot->freeListLock); if (freeit) { pk11_CloseSession(symKey->slot, symKey->session, symKey->sessionOwner); PORT_Free(symKey); } PK11_FreeSlot(slot); if (parent) { PK11_FreeSymKey(parent); } } }
void hmac_init(struct hmac_ctx *ctx, const struct hash_desc *h, const u_char *key, size_t key_len) { #ifndef HAVE_LIBNSS int k; #endif ctx->h = h; ctx->hmac_digest_len = h->hash_digest_len; #ifdef HAVE_LIBNSS /* DBG(DBG_CRYPT, DBG_log("NSS: hmac init")); */ SECStatus status; PK11SymKey *symkey=NULL, *tkey1=NULL; /* PK11SymKey *tkey1=NULL; */ unsigned int klen; chunk_t hmac_opad, hmac_ipad, hmac_pad; memcpy(&symkey, key, key_len); klen = PK11_GetKeyLength(symkey); hmac_opad = hmac_pads(HMAC_OPAD,HMAC_BUFSIZE); hmac_ipad = hmac_pads(HMAC_IPAD,HMAC_BUFSIZE); hmac_pad = hmac_pads(0x00,HMAC_BUFSIZE-klen); if(klen > HMAC_BUFSIZE) { tkey1 = PK11_Derive_osw(symkey, nss_key_derivation_mech(h) , NULL, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, 0); } else { tkey1 = symkey; } PK11SymKey *tkey2 = pk11_derive_wrapper_osw(tkey1, CKM_CONCATENATE_BASE_AND_DATA , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE); PR_ASSERT(tkey2!=NULL); ctx->ikey = pk11_derive_wrapper_osw(tkey2, CKM_XOR_BASE_AND_DATA , hmac_ipad,nss_hash_mech(h), CKA_DIGEST, 0); PR_ASSERT(ctx->ikey !=NULL); ctx->okey = pk11_derive_wrapper_osw(tkey2, CKM_XOR_BASE_AND_DATA , hmac_opad,nss_hash_mech(h), CKA_DIGEST, 0); PR_ASSERT(ctx->okey !=NULL); if(tkey1!=symkey) { PK11_FreeSymKey(tkey1); } PK11_FreeSymKey(tkey2); freeanychunk(hmac_opad); freeanychunk(hmac_ipad); freeanychunk(hmac_pad); ctx->ctx_nss = PK11_CreateDigestContext(nss_hash_oid(h)); PR_ASSERT(ctx->ctx_nss!=NULL); status=PK11_DigestBegin(ctx->ctx_nss); PR_ASSERT(status==SECSuccess); status=PK11_DigestKey(ctx->ctx_nss, ctx->ikey); PR_ASSERT(status==SECSuccess); #else /* Prepare the two pads for the HMAC */ memset(ctx->buf1, '\0', HMAC_BUFSIZE); if (key_len <= HMAC_BUFSIZE) { memcpy(ctx->buf1, key, key_len); } else { h->hash_init(&ctx->hash_ctx); h->hash_update(&ctx->hash_ctx, key, key_len); h->hash_final(ctx->buf1, &ctx->hash_ctx); } memcpy(ctx->buf2, ctx->buf1, HMAC_BUFSIZE); for (k = 0; k < HMAC_BUFSIZE; k++) { ctx->buf1[k] ^= HMAC_IPAD; ctx->buf2[k] ^= HMAC_OPAD; } hmac_reinit(ctx); #endif }
SECStatus SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey, PRUint32 protocolmask, PRUint16 *ciphersuites, int nsuites, PRBool *pcanbypass, void *pwArg) { SECStatus rv; int i; PRUint16 suite; PK11SymKey * pms = NULL; SECKEYPublicKey * srvPubkey = NULL; KeyType privKeytype; PK11SlotInfo * slot = NULL; SECItem param; CK_VERSION version; CK_MECHANISM_TYPE mechanism_array[2]; SECItem enc_pms = {siBuffer, NULL, 0}; PRBool isTLS = PR_FALSE; SSLCipherSuiteInfo csdef; PRBool testrsa = PR_FALSE; PRBool testrsa_export = PR_FALSE; PRBool testecdh = PR_FALSE; PRBool testecdhe = PR_FALSE; #ifdef NSS_ENABLE_ECC SECKEYECParams ecParams = { siBuffer, NULL, 0 }; #endif if (!cert || !srvPrivkey || !ciphersuites || !pcanbypass) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } srvPubkey = CERT_ExtractPublicKey(cert); if (!srvPubkey) return SECFailure; *pcanbypass = PR_TRUE; rv = SECFailure; /* determine which KEAs to test */ /* 0 (SSL_NULL_WITH_NULL_NULL) is used as a list terminator because * SSL3 and TLS specs forbid negotiating that cipher suite number. */ for (i=0; i < nsuites && (suite = *ciphersuites++) != 0; i++) { /* skip SSL2 cipher suites and ones NSS doesn't support */ if (SSL_GetCipherSuiteInfo(suite, &csdef, sizeof(csdef)) != SECSuccess || SSL_IS_SSL2_CIPHER(suite) ) continue; switch (csdef.keaType) { case ssl_kea_rsa: switch (csdef.cipherSuite) { case TLS_RSA_EXPORT1024_WITH_RC4_56_SHA: case TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA: case SSL_RSA_EXPORT_WITH_RC4_40_MD5: case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: testrsa_export = PR_TRUE; } if (!testrsa_export) testrsa = PR_TRUE; break; case ssl_kea_ecdh: if (strcmp(csdef.keaTypeName, "ECDHE") == 0) /* ephemeral? */ testecdhe = PR_TRUE; else testecdh = PR_TRUE; break; case ssl_kea_dh: /* this is actually DHE */ default: continue; } } /* For each protocol try to derive and extract an MS. * Failure of function any function except MS extract means * continue with the next cipher test. Stop testing when the list is * exhausted or when the first MS extract--not derive--fails. */ privKeytype = SECKEY_GetPrivateKeyType(srvPrivkey); protocolmask &= SSL_CBP_SSL3|SSL_CBP_TLS1_0; while (protocolmask) { if (protocolmask & SSL_CBP_SSL3) { isTLS = PR_FALSE; protocolmask ^= SSL_CBP_SSL3; } else { isTLS = PR_TRUE; protocolmask ^= SSL_CBP_TLS1_0; } if (privKeytype == rsaKey && testrsa_export) { if (PK11_GetPrivateModulusLen(srvPrivkey) > EXPORT_RSA_KEY_LENGTH) { *pcanbypass = PR_FALSE; rv = SECSuccess; break; } else testrsa = PR_TRUE; } for (; privKeytype == rsaKey && testrsa; ) { /* TLS_RSA */ unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH]; unsigned int outLen = 0; CK_MECHANISM_TYPE target; SECStatus irv; mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN; mechanism_array[1] = CKM_RSA_PKCS; slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg); if (slot == NULL) { PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND); break; } /* Generate the pre-master secret ... (client side) */ version.major = 3 /*MSB(clientHelloVersion)*/; version.minor = 0 /*LSB(clientHelloVersion)*/; param.data = (unsigned char *)&version; param.len = sizeof version; pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, ¶m, 0, pwArg); PK11_FreeSlot(slot); if (!pms) break; /* now wrap it */ enc_pms.len = SECKEY_PublicKeyStrength(srvPubkey); enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len); if (enc_pms.data == NULL) { PORT_SetError(PR_OUT_OF_MEMORY_ERROR); break; } irv = PK11_PubWrapSymKey(CKM_RSA_PKCS, srvPubkey, pms, &enc_pms); if (irv != SECSuccess) break; PK11_FreeSymKey(pms); pms = NULL; /* now do the server side--check the triple bypass first */ rv = PK11_PrivDecryptPKCS1(srvPrivkey, rsaPmsBuf, &outLen, sizeof rsaPmsBuf, (unsigned char *)enc_pms.data, enc_pms.len); /* if decrypt worked we're done with the RSA test */ if (rv == SECSuccess) { *pcanbypass = PR_TRUE; break; } /* check for fallback to double bypass */ target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE : CKM_SSL3_MASTER_KEY_DERIVE; pms = PK11_PubUnwrapSymKey(srvPrivkey, &enc_pms, target, CKA_DERIVE, 0); rv = ssl_canExtractMS(pms, isTLS, PR_FALSE, pcanbypass); if (rv == SECSuccess && *pcanbypass == PR_FALSE) goto done; break; } /* Check for NULL to avoid double free. * SECItem_FreeItem sets data NULL in secitem.c#265 */ if (enc_pms.data != NULL) { SECITEM_FreeItem(&enc_pms, PR_FALSE); } #ifdef NSS_ENABLE_ECC for (; (privKeytype == ecKey && ( testecdh || testecdhe)) || (privKeytype == rsaKey && testecdhe); ) { CK_MECHANISM_TYPE target; SECKEYPublicKey *keapub = NULL; SECKEYPrivateKey *keapriv; SECKEYPublicKey *cpub = NULL; /* client's ephemeral ECDH keys */ SECKEYPrivateKey *cpriv = NULL; SECKEYECParams *pecParams = NULL; if (privKeytype == ecKey && testecdhe) { /* TLS_ECDHE_ECDSA */ pecParams = &srvPubkey->u.ec.DEREncodedParams; } else if (privKeytype == rsaKey && testecdhe) { /* TLS_ECDHE_RSA */ ECName ec_curve; int serverKeyStrengthInBits; int signatureKeyStrength; int requiredECCbits; /* find a curve of equivalent strength to the RSA key's */ requiredECCbits = PK11_GetPrivateModulusLen(srvPrivkey); if (requiredECCbits < 0) break; requiredECCbits *= BPB; serverKeyStrengthInBits = srvPubkey->u.rsa.modulus.len; if (srvPubkey->u.rsa.modulus.data[0] == 0) { serverKeyStrengthInBits--; } /* convert to strength in bits */ serverKeyStrengthInBits *= BPB; signatureKeyStrength = SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits); if ( requiredECCbits > signatureKeyStrength ) requiredECCbits = signatureKeyStrength; ec_curve = ssl3_GetCurveWithECKeyStrength(SSL3_SUPPORTED_CURVES_MASK, requiredECCbits); rv = ssl3_ECName2Params(NULL, ec_curve, &ecParams); if (rv == SECFailure) { break; } pecParams = &ecParams; } if (testecdhe) { /* generate server's ephemeral keys */ keapriv = SECKEY_CreateECPrivateKey(pecParams, &keapub, NULL); if (!keapriv || !keapub) { if (keapriv) SECKEY_DestroyPrivateKey(keapriv); if (keapub) SECKEY_DestroyPublicKey(keapub); PORT_SetError(SEC_ERROR_KEYGEN_FAIL); rv = SECFailure; break; } } else { /* TLS_ECDH_ECDSA */ keapub = srvPubkey; keapriv = srvPrivkey; pecParams = &srvPubkey->u.ec.DEREncodedParams; } /* perform client side ops */ /* generate a pair of ephemeral keys using server's parms */ cpriv = SECKEY_CreateECPrivateKey(pecParams, &cpub, NULL); if (!cpriv || !cpub) { if (testecdhe) { SECKEY_DestroyPrivateKey(keapriv); SECKEY_DestroyPublicKey(keapub); } PORT_SetError(SEC_ERROR_KEYGEN_FAIL); rv = SECFailure; break; } /* now do the server side */ /* determine the PMS using client's public value */ target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE_DH : CKM_SSL3_MASTER_KEY_DERIVE_DH; pms = PK11_PubDeriveWithKDF(keapriv, cpub, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, CKD_NULL, NULL, NULL); rv = ssl_canExtractMS(pms, isTLS, PR_TRUE, pcanbypass); SECKEY_DestroyPrivateKey(cpriv); SECKEY_DestroyPublicKey(cpub); if (testecdhe) { SECKEY_DestroyPrivateKey(keapriv); SECKEY_DestroyPublicKey(keapub); } if (rv == SECSuccess && *pcanbypass == PR_FALSE) goto done; break; } /* Check for NULL to avoid double free. */ if (ecParams.data != NULL) { PORT_Free(ecParams.data); ecParams.data = NULL; } #endif /* NSS_ENABLE_ECC */ if (pms) PK11_FreeSymKey(pms); } /* *pcanbypass has been set */ rv = SECSuccess; done: if (pms) PK11_FreeSymKey(pms); /* Check for NULL to avoid double free. * SECItem_FreeItem sets data NULL in secitem.c#265 */ if (enc_pms.data != NULL) { SECITEM_FreeItem(&enc_pms, PR_FALSE); } #ifdef NSS_ENABLE_ECC if (ecParams.data != NULL) { PORT_Free(ecParams.data); ecParams.data = NULL; } #endif /* NSS_ENABLE_ECC */ if (srvPubkey) { SECKEY_DestroyPublicKey(srvPubkey); srvPubkey = NULL; } return rv; }
static SECStatus aes_decrypt_buf( const unsigned char *key, unsigned int keysize, const unsigned char *iv, unsigned int ivsize, unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, const unsigned char *input, unsigned int inputlen, const unsigned char *aad, unsigned int aadlen, const unsigned char *tag, unsigned int tagsize) { SECStatus rv = SECFailure; unsigned char concatenated[11*16]; /* 1 to 11 blocks */ SECItem key_item; PK11SlotInfo *slot = NULL; PK11SymKey *symKey = NULL; CK_GCM_PARAMS gcm_params; SECItem param; if (inputlen + tagsize > sizeof(concatenated)) { fprintf(stderr, "aes_decrypt_buf: local buffer too small\n"); goto loser; } memcpy(concatenated, input, inputlen); memcpy(concatenated + inputlen, tag, tagsize); /* Import key into NSS. */ key_item.type = siBuffer; key_item.data = (unsigned char *) key; /* const cast */ key_item.len = keysize; slot = PK11_GetInternalSlot(); symKey = PK11_ImportSymKey(slot, CKM_AES_GCM, PK11_OriginUnwrap, CKA_DECRYPT, &key_item, NULL); PK11_FreeSlot(slot); slot = NULL; if (!symKey) { fprintf(stderr, "PK11_ImportSymKey failed\n"); goto loser; } gcm_params.pIv = (unsigned char *) iv; gcm_params.ulIvLen = ivsize; gcm_params.pAAD = (unsigned char *) aad; gcm_params.ulAADLen = aadlen; gcm_params.ulTagBits = tagsize * 8; param.type = siBuffer; param.data = (unsigned char *) &gcm_params; param.len = sizeof(gcm_params); if (PK11_Decrypt(symKey, CKM_AES_GCM, ¶m, output, outputlen, maxoutputlen, concatenated, inputlen + tagsize) != SECSuccess) { goto loser; } rv = SECSuccess; loser: if (symKey != NULL) { PK11_FreeSymKey(symKey); } return rv; }
int main(int argc, char **argv) { CK_MECHANISM_TYPE hashMech; PK11SlotInfo* slot = NULL; PK11SymKey* SymKey = NULL; SECItem SecParam; PK11Context* HashContext = NULL; SECItem keyItem; SECStatus rv, rv1, rv2; unsigned char buf1[1024], buf2[1024]; char data[1024]; int i; unsigned int tmp2_outlen; /* Initialize NSS * * If your application code has already initialized NSS, you can skip it * * here. * * This code uses the simplest of the Init functions, which does not * * require a NSS database to exist * */ rv = NSS_NoDB_Init("."); if (rv != SECSuccess) { fprintf(stderr, "NSS initialization failed (err %d)\n", PR_GetError()); goto out; } /* choose mechanism: CKM_DES_CBC_PAD, CKM_DES3_ECB, CKM_DES3_CBC..... * * Note that some mechanisms (*_PAD) imply the padding is handled for you * * by NSS. If you choose something else, then data padding is the * * application's responsibility * */ hashMech = CKM_SHA_1_HMAC; slot = PK11_GetBestSlot(hashMech, NULL); /* slot = PK11_GetInternalKeySlot(); is a simpler alternative but in * * theory, it *may not* return the optimal slot for the operation. For * * DES ops, Internal slot is typically the best slot * */ if (slot == NULL) { fprintf(stderr, "Unable to find security device (err %d)\n", PR_GetError()); goto out; } /* NSS passes blobs around as SECItems. These contain a pointer to * * data and a length. Turn the raw key into a SECItem. */ keyItem.type = siBuffer; keyItem.data = gKey; keyItem.len = sizeof(gKey); /* Turn the raw key into a key object. We use PK11_OriginUnwrap * * to indicate the key was unwrapped - which is what should be done * * normally anyway - using raw keys isn't a good idea */ SymKey = PK11_ImportSymKey(slot, hashMech, PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL); if (SymKey == NULL) { fprintf(stderr, "Failure to import key into NSS (err %d)\n", PR_GetError()); goto out; } SecParam.type = siBuffer; SecParam.data = 0; SecParam.len = 0; /* sample data we'll hash */ strcpy(data, "Hash me!"); fprintf(stderr, "Clear Data: %s\n", data); /* ========================= START SECTION ============================= */ /* If using the the same key and iv over and over, stuff before this */ /* section and after this section needs to be done only ONCE */ /* Create cipher context */ HashContext = PK11_CreateContextBySymKey(hashMech, CKA_SIGN, SymKey, &SecParam); if (!HashContext) { fprintf(stderr, "no hash context today?\n"); goto out; } if (PK11_DigestBegin(HashContext) != SECSuccess) { fprintf(stderr, "hash doesn't begin?\n"); goto out; } rv1 = PK11_DigestOp(HashContext, (unsigned char *)data, strlen(data)+1); rv2 = PK11_DigestFinal(HashContext, buf2, &tmp2_outlen, SHA1_BLOCK_LENGTH); PK11_DestroyContext(HashContext, PR_TRUE); if (rv1 != SECSuccess || rv2 != SECSuccess) goto out; fprintf(stderr, "Hash Data: "); for (i=0; i<tmp2_outlen; i++) fprintf(stderr, "%02x ", buf2[i]); fprintf(stderr, "\n"); /* =========================== END SECTION ============================= */ /* ========================= START SECTION ============================= */ /* If using the the same key and iv over and over, stuff before this */ /* section and after this section needs to be done only ONCE */ memset(buf1, 0, sizeof(buf1)); memset(buf2, 0, sizeof(buf2)); /* Create cipher context */ HashContext = PK11_CreateContextBySymKey(hashMech, CKA_SIGN, SymKey, &SecParam); if (!HashContext) { fprintf(stderr, "no hash context today?\n"); goto out; } if (PK11_DigestBegin(HashContext) != SECSuccess) { fprintf(stderr, "hash doesn't begin?\n"); goto out; } rv1 = PK11_DigestOp(HashContext, (unsigned char *)data, 5); rv1 = PK11_DigestOp(HashContext, (unsigned char *)data+5, 4); rv2 = PK11_DigestFinal(HashContext, buf2, &tmp2_outlen, SHA1_BLOCK_LENGTH); PK11_DestroyContext(HashContext, PR_TRUE); if (rv1 != SECSuccess || rv2 != SECSuccess) goto out; fprintf(stderr, "Hash Data: "); for (i=0; i<tmp2_outlen; i++) fprintf(stderr, "%02x ", buf2[i]); fprintf(stderr, "\n"); /* =========================== END SECTION ============================= */ out: if (SymKey) PK11_FreeSymKey(SymKey); return 0; }
/* * Digest a key if possible./ */ SECStatus PK11_DigestKey(PK11Context *context, PK11SymKey *key) { CK_RV crv = CKR_OK; SECStatus rv = SECSuccess; PK11SymKey *newKey = NULL; if (!context || !key) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* if we ran out of session, we need to restore our previously stored * state. */ if (context->slot != key->slot) { newKey = pk11_CopyToSlot(context->slot,CKM_SSL3_SHA1_MAC,CKA_SIGN,key); } else { newKey = PK11_ReferenceSymKey(key); } context->init = PR_FALSE; PK11_EnterContextMonitor(context); if (!context->ownSession) { rv = pk11_restoreContext(context,context->savedData, context->savedLength); if (rv != SECSuccess) { PK11_ExitContextMonitor(context); PK11_FreeSymKey(newKey); return rv; } } if (newKey == NULL) { crv = CKR_KEY_TYPE_INCONSISTENT; if (key->data.data) { crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, key->data.data,key->data.len); } } else { crv=PK11_GETTAB(context->slot)->C_DigestKey(context->session, newKey->objectID); } if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); rv = SECFailure; } /* * handle session starvation case.. use our last session to multiplex */ if (!context->ownSession) { context->savedData = pk11_saveContext(context,context->savedData, &context->savedLength); if (context->savedData == NULL) rv = SECFailure; /* clear out out session for others to use */ pk11_Finalize(context); } PK11_ExitContextMonitor(context); if (newKey) PK11_FreeSymKey(newKey); return rv; }
/* Called from ssl3_SendClientKeyExchange(). */ SECStatus ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) { PK11SymKey *pms = NULL; SECStatus rv = SECFailure; PRBool isTLS, isTLS12; CK_MECHANISM_TYPE target; const namedGroupDef *groupDef; sslEphemeralKeyPair *keyPair = NULL; SECKEYPublicKey *pubKey; PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* Generate ephemeral EC keypair */ if (svrPubKey->keyType != ecKey) { PORT_SetError(SEC_ERROR_BAD_KEY); goto loser; } groupDef = ssl_ECPubKey2NamedGroup(svrPubKey); if (!groupDef) { PORT_SetError(SEC_ERROR_BAD_KEY); goto loser; } rv = ssl_CreateECDHEphemeralKeyPair(groupDef, &keyPair); if (rv != SECSuccess) { ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); goto loser; } pubKey = keyPair->keys->pubKey; PRINT_BUF(50, (ss, "ECDH public value:", pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len)); if (isTLS12) { target = CKM_TLS12_MASTER_KEY_DERIVE_DH; } else if (isTLS) { target = CKM_TLS_MASTER_KEY_DERIVE_DH; } else { target = CKM_SSL3_MASTER_KEY_DERIVE_DH; } /* Determine the PMS */ pms = PK11_PubDeriveWithKDF(keyPair->keys->privKey, svrPubKey, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, CKD_NULL, NULL, NULL); if (pms == NULL) { (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; } rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, pubKey->u.ec.publicValue.len + 1); if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ } rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len, 1); if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ } rv = ssl3_InitPendingCipherSpec(ss, pms); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; } PK11_FreeSymKey(pms); ssl_FreeEphemeralKeyPair(keyPair); return SECSuccess; loser: if (pms) PK11_FreeSymKey(pms); if (keyPair) ssl_FreeEphemeralKeyPair(keyPair); return SECFailure; }
SECStatus tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash, PK11SymKey **prkp) { CK_NSS_HKDFParams params; SECItem paramsi; SECStatus rv; SECItem *salt; PK11SymKey *prk; static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX]; PK11SymKey *zeroKey = NULL; PK11SlotInfo *slot = NULL; PK11SymKey *ikm2; params.bExtract = CK_TRUE; params.bExpand = CK_FALSE; params.pInfo = NULL; params.ulInfoLen = 0UL; if (ikm1) { /* TODO([email protected]): This violates the PKCS#11 key boundary * but is imposed on us by the present HKDF interface. */ rv = PK11_ExtractKeyValue(ikm1); if (rv != SECSuccess) return rv; salt = PK11_GetKeyData(ikm1); if (!salt) return SECFailure; params.pSalt = salt->data; params.ulSaltLen = salt->len; PORT_Assert(salt->len > 0); } else { /* Per documentation for CKM_NSS_HKDF_*: * * If the optional salt is given, it is used; otherwise, the salt is * set to a sequence of zeros equal in length to the HMAC output. */ params.pSalt = NULL; params.ulSaltLen = 0UL; } paramsi.data = (unsigned char *)¶ms; paramsi.len = sizeof(params); PORT_Assert(kTlsHkdfInfo[baseHash].pkcs11Mech); PORT_Assert(kTlsHkdfInfo[baseHash].hashSize); PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash); /* A zero ikm2 is a key of hash-length 0s. */ if (!ikm2in) { SECItem zeroItem = { siBuffer, (unsigned char *)zeroKeyBuf, kTlsHkdfInfo[baseHash].hashSize }; slot = PK11_GetInternalSlot(); if (!slot) { return SECFailure; } zeroKey = PK11_ImportSymKey(slot, kTlsHkdfInfo[baseHash].pkcs11Mech, PK11_OriginUnwrap, CKA_DERIVE, &zeroItem, NULL); if (!zeroKey) return SECFailure; ikm2 = zeroKey; } else { ikm2 = ikm2in; } PORT_Assert(ikm2); PRINT_BUF(50, (NULL, "HKDF Extract: IKM1/Salt", params.pSalt, params.ulSaltLen)); PRINT_KEY(50, (NULL, "HKDF Extract: IKM2", ikm2)); prk = PK11_Derive(ikm2, kTlsHkdfInfo[baseHash].pkcs11Mech, ¶msi, kTlsHkdfInfo[baseHash].pkcs11Mech, CKA_DERIVE, kTlsHkdfInfo[baseHash].hashSize); if (zeroKey) PK11_FreeSymKey(zeroKey); if (slot) PK11_FreeSlot(slot); if (!prk) return SECFailure; PRINT_KEY(50, (NULL, "HKDF Extract", prk)); *prkp = prk; return SECSuccess; }
char * crypto_encrypt (const char *cipher, const guint8 *data, gsize data_len, const char *iv, gsize iv_len, const char *key, gsize key_len, gsize *out_len, GError **error) { SECStatus ret; CK_MECHANISM_TYPE cipher_mech = CKM_DES3_CBC_PAD; PK11SlotInfo *slot = NULL; SECItem key_item = { .data = (unsigned char *) key, .len = key_len }; SECItem iv_item = { .data = (unsigned char *) iv, .len = iv_len }; PK11SymKey *sym_key = NULL; SECItem *sec_param = NULL; PK11Context *ctx = NULL; unsigned char *output, *padded_buf; gsize output_len; int encrypted_len = 0, i; gboolean success = FALSE; gsize padded_buf_len, pad_len; if (!crypto_init (error)) return NULL; if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) cipher_mech = CKM_DES3_CBC_PAD; else if (!strcmp (cipher, CIPHER_AES_CBC)) cipher_mech = CKM_AES_CBC_PAD; else { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_UNKNOWN_CIPHER, _("Private key cipher '%s' was unknown."), cipher); return NULL; } /* If data->len % ivlen == 0, then we add another complete block * onto the end so that the decrypter knows there's padding. */ pad_len = iv_len - (data_len % iv_len); output_len = padded_buf_len = data_len + pad_len; padded_buf = g_malloc0 (padded_buf_len); memcpy (padded_buf, data, data_len); for (i = 0; i < pad_len; i++) padded_buf[data_len + i] = (guint8) (pad_len & 0xFF); output = g_malloc0 (output_len); slot = PK11_GetBestSlot (cipher_mech, NULL); if (!slot) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_FAILED, _("Failed to initialize the encryption cipher slot.")); goto out; } sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL); if (!sym_key) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to set symmetric key for encryption.")); goto out; } sec_param = PK11_ParamFromIV (cipher_mech, &iv_item); if (!sec_param) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to set IV for encryption.")); goto out; } ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_ENCRYPT, sym_key, sec_param); if (!ctx) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to initialize the encryption context.")); goto out; } ret = PK11_CipherOp (ctx, output, &encrypted_len, output_len, padded_buf, padded_buf_len); if (ret != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to encrypt: %d."), PORT_GetError ()); goto out; } if (encrypted_len != output_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Unexpected amount of data after encrypting.")); goto out; } *out_len = encrypted_len; success = TRUE; out: if (ctx) PK11_DestroyContext (ctx, PR_TRUE); if (sym_key) PK11_FreeSymKey (sym_key); if (sec_param) SECITEM_FreeItem (sec_param, PR_TRUE); if (slot) PK11_FreeSlot (slot); memset (padded_buf, 0, padded_buf_len); g_free (padded_buf); if (!success) { memset (output, 0, output_len); g_free (output); output = NULL; } return (char *) output; } NMCryptoFileFormat crypto_verify_cert (const unsigned char *data, gsize len, GError **error) { CERTCertificate *cert; if (!crypto_init (error)) return NM_CRYPTO_FILE_FORMAT_UNKNOWN; /* Try DER/PEM first */ cert = CERT_DecodeCertFromPackage ((char *) data, len); if (!cert) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA, _("Couldn't decode certificate: %d"), PORT_GetError()); return NM_CRYPTO_FILE_FORMAT_UNKNOWN; } CERT_DestroyCertificate (cert); return NM_CRYPTO_FILE_FORMAT_X509; } gboolean crypto_verify_pkcs12 (const guint8 *data, gsize data_len, const char *password, GError **error) { SEC_PKCS12DecoderContext *p12ctx = NULL; SECItem pw = { 0 }; PK11SlotInfo *slot = NULL; SECStatus s; gunichar2 *ucs2_password; glong ucs2_chars = 0; #ifndef WORDS_BIGENDIAN guint16 *p; #endif /* WORDS_BIGENDIAN */ if (error) g_return_val_if_fail (*error == NULL, FALSE); if (!crypto_init (error)) return FALSE; /* PKCS#12 passwords are apparently UCS2 BIG ENDIAN, and NSS doesn't do * any conversions for us. */ if (password && *password) { if (!g_utf8_validate (password, -1, NULL)) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_PASSWORD, _("Password must be UTF-8")); return FALSE; } ucs2_password = g_utf8_to_utf16 (password, strlen (password), NULL, &ucs2_chars, NULL); /* Can't fail if g_utf8_validate() succeeded */ g_return_val_if_fail (ucs2_password != NULL && ucs2_chars != 0, FALSE); ucs2_chars *= 2; /* convert # UCS2 characters -> bytes */ pw.data = PORT_ZAlloc(ucs2_chars + 2); memcpy (pw.data, ucs2_password, ucs2_chars); pw.len = ucs2_chars + 2; /* include terminating NULL */ memset (ucs2_password, 0, ucs2_chars); g_free (ucs2_password); #ifndef WORDS_BIGENDIAN for (p = (guint16 *) pw.data; p < (guint16 *) (pw.data + pw.len); p++) *p = GUINT16_SWAP_LE_BE (*p); #endif /* WORDS_BIGENDIAN */ } else { /* NULL password */ pw.data = NULL; pw.len = 0; } slot = PK11_GetInternalKeySlot(); p12ctx = SEC_PKCS12DecoderStart (&pw, slot, NULL, NULL, NULL, NULL, NULL, NULL); if (!p12ctx) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_FAILED, _("Couldn't initialize PKCS#12 decoder: %d"), PORT_GetError()); goto error; } s = SEC_PKCS12DecoderUpdate (p12ctx, (guint8 *)data, data_len); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA, _("Couldn't decode PKCS#12 file: %d"), PORT_GetError()); goto error; } s = SEC_PKCS12DecoderVerify (p12ctx); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Couldn't verify PKCS#12 file: %d"), PORT_GetError()); goto error; } SEC_PKCS12DecoderFinish (p12ctx); SECITEM_ZfreeItem (&pw, PR_FALSE); return TRUE; error: if (p12ctx) SEC_PKCS12DecoderFinish (p12ctx); if (slot) PK11_FreeSlot(slot); SECITEM_ZfreeItem (&pw, PR_FALSE); return FALSE; }
static int sm_encrypt(CamelCipherContext *context, const char *userid, GPtrArray *recipients, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex) { struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv; /*NSSCMSRecipientInfo **recipient_infos;*/ CERTCertificate **recipient_certs = NULL; NSSCMSContentInfo *cinfo; PK11SymKey *bulkkey = NULL; SECOidTag bulkalgtag; int bulkkeysize, i; CK_MECHANISM_TYPE type; PK11SlotInfo *slot; PLArenaPool *poolp; NSSCMSMessage *cmsg = NULL; NSSCMSEnvelopedData *envd; NSSCMSEncoderContext *enc = NULL; CamelStreamMem *mem; CamelStream *ostream = NULL; CamelDataWrapper *dw; CamelContentType *ct; poolp = PORT_NewArena(1024); if (poolp == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM)); return -1; } /* Lookup all recipients certs, for later working */ recipient_certs = (CERTCertificate **)PORT_ArenaZAlloc(poolp, sizeof(*recipient_certs[0])*(recipients->len + 1)); if (recipient_certs == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM)); goto fail; } for (i=0;i<recipients->len;i++) { recipient_certs[i] = CERT_FindCertByNicknameOrEmailAddr(p->certdb, recipients->pdata[i]); if (recipient_certs[i] == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find certificate for `%s'"), recipients->pdata[i]); goto fail; } } /* Find a common algorithm, probably 3DES anyway ... */ if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipient_certs, &bulkalgtag, &bulkkeysize) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find common bulk encryption algorithm")); goto fail; } /* Generate a new bulk key based on the common algorithm - expensive */ type = PK11_AlgtagToMechanism(bulkalgtag); slot = PK11_GetBestSlot(type, context); if (slot == NULL) { /* PORT_GetError(); ?? */ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot allocate slot for encryption bulk key")); goto fail; } bulkkey = PK11_KeyGen(slot, type, NULL, bulkkeysize/8, context); PK11_FreeSlot(slot); /* Now we can start building the message */ /* msg->envelopedData->data */ cmsg = NSS_CMSMessage_Create(NULL); if (cmsg == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Message")); goto fail; } envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, bulkkeysize); if (envd == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Enveloped data")); goto fail; } cinfo = NSS_CMSMessage_GetContentInfo(cmsg); if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS Enveloped data")); goto fail; } cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd); if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS data object")); goto fail; } /* add recipient certs */ for (i=0;recipient_certs[i];i++) { NSSCMSRecipientInfo *ri = NSS_CMSRecipientInfo_Create(cmsg, recipient_certs[i]); if (ri == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Recipient information")); goto fail; } if (NSS_CMSEnvelopedData_AddRecipient(envd, ri) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS Recipient information")); goto fail; } } /* dump it out */ ostream = camel_stream_mem_new(); enc = NSS_CMSEncoder_Start(cmsg, sm_write_stream, ostream, NULL, NULL, NULL, NULL, sm_decrypt_key, bulkkey, NULL, NULL); if (enc == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create encoder context")); goto fail; } /* FIXME: Stream the input */ /* FIXME: Canonicalise the input? */ mem = (CamelStreamMem *)camel_stream_mem_new(); camel_data_wrapper_write_to_stream((CamelDataWrapper *)ipart, (CamelStream *)mem); if (NSS_CMSEncoder_Update(enc, (char *) mem->buffer->data, mem->buffer->len) != SECSuccess) { NSS_CMSEncoder_Cancel(enc); camel_object_unref(mem); camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to add data to encoder")); goto fail; } camel_object_unref(mem); if (NSS_CMSEncoder_Finish(enc) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to encode data")); goto fail; } PK11_FreeSymKey(bulkkey); NSS_CMSMessage_Destroy(cmsg); for (i=0;recipient_certs[i];i++) CERT_DestroyCertificate(recipient_certs[i]); PORT_FreeArena(poolp, PR_FALSE); dw = camel_data_wrapper_new(); camel_data_wrapper_construct_from_stream(dw, ostream); camel_object_unref(ostream); dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY; ct = camel_content_type_new("application", "x-pkcs7-mime"); camel_content_type_set_param(ct, "name", "smime.p7m"); camel_content_type_set_param(ct, "smime-type", "enveloped-data"); camel_data_wrapper_set_mime_type_field(dw, ct); camel_content_type_unref(ct); camel_medium_set_content_object((CamelMedium *)opart, dw); camel_object_unref(dw); camel_mime_part_set_disposition(opart, "attachment"); camel_mime_part_set_filename(opart, "smime.p7m"); camel_mime_part_set_description(opart, "S/MIME Encrypted Message"); camel_mime_part_set_encoding(opart, CAMEL_TRANSFER_ENCODING_BASE64); return 0; fail: if (ostream) camel_object_unref(ostream); if (cmsg) NSS_CMSMessage_Destroy(cmsg); if (bulkkey) PK11_FreeSymKey(bulkkey); if (recipient_certs) { for (i=0;recipient_certs[i];i++) CERT_DestroyCertificate(recipient_certs[i]); } PORT_FreeArena(poolp, PR_FALSE); return -1; }
static int xmlSecNssKWAesOp(const xmlSecByte *key, xmlSecSize keySize, const xmlSecByte *in, xmlSecSize inSize, xmlSecByte *out, xmlSecSize outSize, int enc) { xmlSecByte block[XMLSEC_NSS_AES_BLOCK_SIZE]; xmlSecByte *p; int N, i, j, t; int result = -1; PK11SymKey *aeskey = NULL; xmlSecAssert2(key != NULL, -1); xmlSecAssert2(keySize > 0, -1); xmlSecAssert2(in != NULL, -1); xmlSecAssert2(inSize > 0, -1); xmlSecAssert2(out != NULL, -1); xmlSecAssert2(outSize >= inSize + 8, -1); if (enc == 1) { aeskey = xmlSecNssMakeAesKey(key, keySize, enc); if(aeskey == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "xmlSecNssMakeAesKey", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } /* prepend magic block */ if(in != out) { memcpy(out + XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE, in, inSize); } else { memmove(out + XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE, out, inSize); } memcpy(out, xmlSecNssKWAesMagicBlock, XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE); N = (inSize / 8); if(N == 1) { xmlSecNssAesOp(aeskey, out, out, enc); } else { for(j = 0; j <= 5; ++j) { for(i = 1; i <= N; ++i) { t = i + (j * N); p = out + i * 8; memcpy(block, out, 8); memcpy(block + 8, p, 8); xmlSecNssAesOp(aeskey, block, block, enc); block[7] ^= t; memcpy(out, block, 8); memcpy(p, block + 8, 8); } } } result = inSize + 8; } else { aeskey = xmlSecNssMakeAesKey(key, keySize, enc); if(aeskey == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "xmlSecNssMakeAesKey", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } /* copy input */ if(in != out) { memcpy(out, in, inSize); } N = (inSize / 8) - 1; if(N == 1) { xmlSecNssAesOp(aeskey, out, out, enc); } else { for(j = 5; j >= 0; --j) { for(i = N; i > 0; --i) { t = i + (j * N); p = out + i * 8; memcpy(block, out, 8); memcpy(block + 8, p, 8); block[7] ^= t; xmlSecNssAesOp(aeskey, block, block, enc); memcpy(out, block, 8); memcpy(p, block + 8, 8); } } } /* do not left data in memory */ memset(block, 0, sizeof(block)); if(memcmp(xmlSecNssKWAesMagicBlock, out, XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE) != 0) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, NULL, XMLSEC_ERRORS_R_INVALID_DATA, "bad magic block"); goto done; } memmove(out, out + XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE, inSize - XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE); result = (inSize - XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE); } done: if (aeskey != NULL) { PK11_FreeSymKey(aeskey); } return (result); }
/* ** Called from ssl3_HandleClientKeyExchange() */ SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length, sslKeyPair *serverKeyPair) { PK11SymKey *pms; SECStatus rv; SECKEYPublicKey clntPubKey; CK_MECHANISM_TYPE target; PRBool isTLS, isTLS12; int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); clntPubKey.keyType = ecKey; clntPubKey.u.ec.DEREncodedParams.len = serverKeyPair->pubKey->u.ec.DEREncodedParams.len; clntPubKey.u.ec.DEREncodedParams.data = serverKeyPair->pubKey->u.ec.DEREncodedParams.data; rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue, 1, &b, &length); if (rv != SECSuccess) { PORT_SetError(errCode); return SECFailure; } /* we have to catch the case when the client's public key has length 0. */ if (!clntPubKey.u.ec.publicValue.len) { (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); PORT_SetError(errCode); return SECFailure; } isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); if (isTLS12) { target = CKM_TLS12_MASTER_KEY_DERIVE_DH; } else if (isTLS) { target = CKM_TLS_MASTER_KEY_DERIVE_DH; } else { target = CKM_SSL3_MASTER_KEY_DERIVE_DH; } /* Determine the PMS */ pms = PK11_PubDeriveWithKDF(serverKeyPair->privKey, &clntPubKey, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, CKD_NULL, NULL, NULL); if (pms == NULL) { /* last gasp. */ errCode = ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); PORT_SetError(errCode); return SECFailure; } rv = ssl3_InitPendingCipherSpec(ss, pms); PK11_FreeSymKey(pms); if (rv != SECSuccess) { /* error code set by ssl3_InitPendingCipherSpec */ return SECFailure; } return SECSuccess; }
static int xmlSecNssKWAesOp(const xmlSecByte *key, xmlSecSize keySize, const xmlSecByte *in, xmlSecSize inSize, xmlSecByte *out, xmlSecSize outSize, int enc) { CK_MECHANISM_TYPE cipherMech; PK11SlotInfo* slot = NULL; PK11SymKey* aeskey = NULL; SECItem* SecParam = NULL; PK11Context* EncContext = NULL; SECItem keyItem; SECStatus rv; int result_len = -1; int tmp1_outlen; unsigned int tmp2_outlen; xmlSecAssert2(key != NULL, -1); xmlSecAssert2(keySize > 0, -1); xmlSecAssert2(in != NULL, -1); xmlSecAssert2(inSize > 0, -1); xmlSecAssert2(out != NULL, -1); xmlSecAssert2(outSize >= inSize + 8, -1); cipherMech = CKM_NETSCAPE_AES_KEY_WRAP; slot = PK11_GetBestSlot(cipherMech, NULL); if (slot == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_GetBestSlot", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } keyItem.data = (unsigned char *)key; keyItem.len = keySize; aeskey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, enc ? CKA_ENCRYPT : CKA_DECRYPT, &keyItem, NULL); if (aeskey == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_ImportSymKey", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } SecParam = PK11_ParamFromIV(cipherMech, NULL); if (SecParam == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_ParamFromIV", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } EncContext = PK11_CreateContextBySymKey(cipherMech, enc ? CKA_ENCRYPT : CKA_DECRYPT, aeskey, SecParam); if (EncContext == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_CreateContextBySymKey", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } tmp1_outlen = tmp2_outlen = 0; rv = PK11_CipherOp(EncContext, out, &tmp1_outlen, outSize, (unsigned char *)in, inSize); if (rv != SECSuccess) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_CipherOp", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } rv = PK11_DigestFinal(EncContext, out+tmp1_outlen, &tmp2_outlen, outSize-tmp1_outlen); if (rv != SECSuccess) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_DigestFinal", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } result_len = tmp1_outlen + tmp2_outlen; done: if (slot) { PK11_FreeSlot(slot); } if (aeskey) { PK11_FreeSymKey(aeskey); } if (SecParam) { SECITEM_FreeItem(SecParam, PR_TRUE); } if (EncContext) { PK11_DestroyContext(EncContext, PR_TRUE); } return(result_len); }
/* Called from ssl3_SendClientKeyExchange(). */ SECStatus ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) { PK11SymKey * pms = NULL; SECStatus rv = SECFailure; PRBool isTLS, isTLS12; CK_MECHANISM_TYPE target; SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */ SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* Generate ephemeral EC keypair */ if (svrPubKey->keyType != ecKey) { PORT_SetError(SEC_ERROR_BAD_KEY); goto loser; } /* XXX SHOULD CALL ssl3_CreateECDHEphemeralKeys here, instead! */ privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams, &pubKey, ss->pkcs11PinArg); if (!privKey || !pubKey) { ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); rv = SECFailure; goto loser; } PRINT_BUF(50, (ss, "ECDH public value:", pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len)); if (isTLS12) { target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; } else if (isTLS) { target = CKM_TLS_MASTER_KEY_DERIVE_DH; } else { target = CKM_SSL3_MASTER_KEY_DERIVE_DH; } /* Determine the PMS */ pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, CKD_NULL, NULL, NULL); if (pms == NULL) { SSL3AlertDescription desc = illegal_parameter; (void)SSL3_SendAlert(ss, alert_fatal, desc); ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; } SECKEY_DestroyPrivateKey(privKey); privKey = NULL; rv = ssl3_InitPendingCipherSpec(ss, pms); PK11_FreeSymKey(pms); pms = NULL; if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; } rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, pubKey->u.ec.publicValue.len + 1); if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ } rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len, 1); SECKEY_DestroyPublicKey(pubKey); pubKey = NULL; if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ } rv = SECSuccess; loser: if(pms) PK11_FreeSymKey(pms); if(privKey) SECKEY_DestroyPrivateKey(privKey); if(pubKey) SECKEY_DestroyPublicKey(pubKey); return rv; }
void genkey(int id) { PK11SlotInfo* slot = NULL; PK11SymKey* key = NULL; SECItem keyiditem; int keyid[1]; CK_MECHANISM_TYPE cipherMech; /* using CKM_AES_CBC_PAD mechanism for example */ cipherMech = CKM_AES_CBC_PAD; slot = PK11_GetInternalKeySlot(); /* slot = PK11_GetBestSlot(cipherMech, NULL); didn't work. * Error code: token is read-only. ?? */ if (slot == NULL) { fprintf(stderr, "Unable to find security device (err %d)\n", PR_GetError()); return; } keyid[0] = id; keyiditem.type = siBuffer; keyiditem.data = (void *)keyid; keyiditem.len = sizeof(keyid[0]); /* Note: keysize must be 0 for fixed key-length algorithms like DES. * Since we're using AES in this example, we're specifying * one of the valid keysizes (16, 24, 32) */ key = PK11_TokenKeyGen(slot, cipherMech, 0, 32 /*keysize*/, &keyiditem, PR_TRUE, 0); if (key == NULL) { fprintf(stderr, "PK11_TokenKeyGen failed (err %d)\n", PR_GetError()); PK11_FreeSlot(slot); return; } fprintf(stderr, "key length of generated key is %d\n", PK11_GetKeyLength(key)); fprintf(stderr, "mechanism of key is %d (asked for %d)\n", PK11_GetMechanism(key), cipherMech); PK11_FreeSymKey(key); key = PK11_FindFixedKey(slot, cipherMech, &keyiditem, 0); if (key == NULL) { fprintf(stderr, "PK11_FindFixedKey failed (err %d)\n", PR_GetError()); PK11_FreeSlot(slot); return; } fprintf(stderr, "Found key!\n"); fprintf(stderr, "key length of generated key is %d\n", PK11_GetKeyLength(key)); fprintf(stderr, "mechanism of key is %d (asked for %d)\n", PK11_GetMechanism(key), cipherMech); PK11_FreeSymKey(key); PK11_FreeSlot(slot); }