/* * find the best key wrap mechanism for this slot. */ CK_MECHANISM_TYPE PK11_GetBestWrapMechanism(PK11SlotInfo *slot) { int i; for (i=0; i < wrapMechanismCount; i++) { if (PK11_DoesMechanism(slot,wrapMechanismList[i])) { return wrapMechanismList[i]; } } return CKM_INVALID_MECHANISM; }
static CK_MECHANISM_TYPE crmf_get_best_privkey_wrap_mechanism(PK11SlotInfo *slot) { CK_MECHANISM_TYPE privKeyPadMechs[] = { CKM_DES3_CBC_PAD, CKM_CAST5_CBC_PAD, CKM_DES_CBC_PAD, CKM_IDEA_CBC_PAD, CKM_CAST3_CBC_PAD, CKM_CAST_CBC_PAD, CKM_RC5_CBC_PAD, CKM_RC2_CBC_PAD, CKM_CDMF_CBC_PAD }; int mechCount = sizeof(privKeyPadMechs)/sizeof(privKeyPadMechs[0]); int i; for (i=0; i < mechCount; i++) { if (PK11_DoesMechanism(slot, privKeyPadMechs[i])) { return privKeyPadMechs[i]; } } return CKM_INVALID_MECHANISM; }
/* RSA sign/decrypt with the key, signature happens 'in place' */ vcard_7816_status_t vcard_emul_rsa_op(VCard *card, VCardKey *key, unsigned char *buffer, int buffer_size) { SECKEYPrivateKey *priv_key; unsigned signature_len; PK11SlotInfo *slot; SECStatus rv; unsigned char buf[2048]; unsigned char *bp = NULL; int pad_len; vcard_7816_status_t ret = VCARD7816_STATUS_SUCCESS; if ((!nss_emul_init) || (key == NULL)) { /* couldn't get the key, indicate that we aren't logged in */ return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; } priv_key = vcard_emul_get_nss_key(key); if (priv_key == NULL) { /* couldn't get the key, indicate that we aren't logged in */ return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; } slot = vcard_emul_card_get_slot(card); /* * this is only true of the rsa signature */ signature_len = PK11_SignatureLen(priv_key); if (buffer_size != signature_len) { return VCARD7816_STATUS_ERROR_DATA_INVALID; } /* be able to handle larger keys if necessariy */ bp = &buf[0]; if (sizeof(buf) < signature_len) { bp = g_malloc(signature_len); } /* * do the raw operations. Some tokens claim to do CKM_RSA_X_509, but then * choke when they try to do the actual operations. Try to detect * those cases and treat them as if the token didn't claim support for * X_509. */ if (key->failedX509 != VCardEmulTrue && PK11_DoesMechanism(slot, CKM_RSA_X_509)) { rv = PK11_PrivDecryptRaw(priv_key, bp, &signature_len, signature_len, buffer, buffer_size); if (rv == SECSuccess) { assert(buffer_size == signature_len); memcpy(buffer, bp, signature_len); key->failedX509 = VCardEmulFalse; goto cleanup; } /* * we've had a successful X509 operation, this failure must be * somethine else */ if (key->failedX509 == VCardEmulFalse) { ret = vcard_emul_map_error(PORT_GetError()); goto cleanup; } /* * key->failedX509 must be Unknown at this point, try the * non-x_509 case */ } /* token does not support CKM_RSA_X509, emulate that with CKM_RSA_PKCS */ /* is this a PKCS #1 formatted signature? */ if ((buffer[0] == 0) && (buffer[1] == 1)) { int i; for (i = 2; i < buffer_size; i++) { /* rsa signature pad */ if (buffer[i] != 0xff) { break; } } if ((i < buffer_size) && (buffer[i] == 0)) { /* yes, we have a properly formated PKCS #1 signature */ /* * NOTE: even if we accidentally got an encrypt buffer, which * through shear luck started with 00, 01, ff, 00, it won't matter * because the resulting Sign operation will effectively decrypt * the real buffer. */ SECItem signature; SECItem hash; i++; hash.data = &buffer[i]; hash.len = buffer_size - i; signature.data = bp; signature.len = signature_len; rv = PK11_Sign(priv_key, &signature, &hash); if (rv != SECSuccess) { ret = vcard_emul_map_error(PORT_GetError()); goto cleanup; } assert(buffer_size == signature.len); memcpy(buffer, bp, signature.len); /* * we got here because either the X509 attempt failed, or the * token couldn't do the X509 operation, in either case stay * with the PKCS version for future operations on this key */ key->failedX509 = VCardEmulTrue; goto cleanup; } } pad_len = buffer_size - signature_len; assert(pad_len < 4); /* * OK now we've decrypted the payload, package it up in PKCS #1 for the * upper layer. */ buffer[0] = 0; buffer[1] = 2; /* RSA_encrypt */ pad_len -= 3; /* format is 0 || 2 || pad || 0 || data */ /* * padding for PKCS #1 encrypted data is a string of random bytes. The * random butes protect against potential decryption attacks against RSA. * Since PrivDecrypt has already stripped those bytes, we can't reconstruct * them. This shouldn't matter to the upper level code which should just * strip this code out anyway, so We'll pad with a constant 3. */ memset(&buffer[2], 0x03, pad_len); pad_len += 2; /* index to the end of the pad */ buffer[pad_len] = 0; pad_len++; /* index to the start of the data */ memcpy(&buffer[pad_len], bp, signature_len); /* * we got here because either the X509 attempt failed, or the * token couldn't do the X509 operation, in either case stay * with the PKCS version for future operations on this key */ key->failedX509 = VCardEmulTrue; cleanup: if (bp != buf) { g_free(bp); } return ret; }
/* * CreatePk11PinStore */ int CreatePk11PinStore(Pk11PinStore **out, const char *tokenName, const char *pin) { int err = PIN_SUCCESS; Pk11PinStore *store; do { store = (Pk11PinStore*)malloc(sizeof(Pk11PinStore)); if (store == 0) { err = PIN_NOMEMORY; break; } /* Low-level init */ store->key = 0; store->params = 0; store->crypt = 0; /* Use the tokenName to find a PKCS11 slot */ store->slot = PK11_FindSlotByName((char *)tokenName); if (store->slot == 0) { err = PIN_NOSUCHTOKEN; break; } /* Check the password/PIN. This allows access to the token */ { SECStatus rv = PK11_CheckUserPassword(store->slot, (char *)pin); if (rv == SECSuccess) ; else if (rv == SECWouldBlock) { /* NSS returns a blocking error when the pin is wrong */ err = PIN_INCORRECTPW; break; } else { err = PIN_SYSTEMERROR; break; } } /* Find the mechanism that this token can do */ { const mech_item *tp; store->mech = 0; for(tp = table;tp < &table[MECH_TABLE_SIZE];tp++) { if (PK11_DoesMechanism(store->slot, tp->type)) { store->mech = (mech_item *)tp; break; } } /* Default to a mechanism (probably on the internal token */ if (store->mech == 0) { store->mech = &dflt_mech; } } /* Generate a key and parameters to do the encryption */ #if NSS_VMAJOR >= 3 && (NSS_VMINOR <= 9 || (NSS_VMINOR <= 10 && NSS_VPATCH == 0)) store->key = PK11_KeyGen(store->slot, store->mech->type, 0, 0, 0); #else store->key = PK11_TokenKeyGenWithFlags(store->slot, store->mech->type, NULL, 0, NULL, CKF_ENCRYPT|CKF_DECRYPT, PR_FALSE, NULL); #endif if (store->key == 0) { /* PR_SetError(xxx); */ err = PIN_SYSTEMERROR; break; } store->params = PK11_GenerateNewParam(store->mech->type, store->key); if (store->params == 0) { err = PIN_SYSTEMERROR; break; } /* Compute the size of the encrypted data including necessary padding */ { int blocksize = PK11_GetBlockSize(store->mech->type, 0); store->length = strlen(pin)+1; /* Compute padded size - 0 means stream cipher */ if (blocksize != 0) { store->length += blocksize - (store->length % blocksize); } store->crypt = (unsigned char *)malloc(store->length); if (!store->crypt) { err = PIN_NOMEMORY; break; } } /* Encrypt */ { unsigned char *plain; PK11Context *ctx; SECStatus rv; int outLen; plain = (unsigned char *)malloc(store->length); if (!plain) { err = PIN_NOMEMORY; break; } /* Pad with 0 bytes */ memset(plain, 0, store->length); strcpy((char *)plain, pin); ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_ENCRYPT, store->key, store->params); if (!ctx) { err = PIN_SYSTEMERROR; break; } do { rv = PK11_CipherOp(ctx, store->crypt, &outLen, store->length, plain, store->length); if (rv) break; rv = PK11_Finalize(ctx); } while(0); PK11_DestroyContext(ctx, PR_TRUE); memset(plain, 0, store->length); free(plain); if (rv) err = PIN_SYSTEMERROR; } } while(0); if (err) { DestroyPk11PinStore(store); store = 0; } *out = store; return err; }
/* * SVRCORE_CreatePk11PinStore */ SVRCOREError SVRCORE_CreatePk11PinStore( SVRCOREPk11PinStore **out, const char *tokenName, const char *pin) { SVRCOREError err; SVRCOREPk11PinStore *store; do { err = SVRCORE_Success; store = (SVRCOREPk11PinStore*)malloc(sizeof *store); if (store == 0) { err = SVRCORE_NoMemory_Error; break; } /* Low-level init */ store->slot = 0; store->key = 0; store->params = 0; store->crypt = 0; /* Use the tokenName to find a PKCS11 slot */ store->slot = PK11_FindSlotByName((char *)tokenName); if (store->slot == 0) { err = SVRCORE_NoSuchToken_Error; break; } /* Check the password/PIN. This allows access to the token */ { SECStatus rv = PK11_CheckUserPassword(store->slot, (char *)pin); if (rv == SECSuccess) ; else if (rv == SECWouldBlock) { err = SVRCORE_IncorrectPassword_Error; break; } else { err = SVRCORE_System_Error; break; } } /* Find the mechanism that this token can do */ { const mech_item *tp; store->mech = 0; for(tp = table;tp < &table[MECH_TABLE_SIZE];tp++) { if (PK11_DoesMechanism(store->slot, tp->type)) { store->mech = tp; break; } } /* Default to a mechanism (probably on the internal token */ if (store->mech == 0) store->mech = &dflt_mech; } /* Generate a key and parameters to do the encryption */ store->key = PK11_TokenKeyGenWithFlags(store->slot, store->mech->type, 0, 0, 0, CKF_ENCRYPT|CKF_DECRYPT, 0, 0); if (store->key == 0) { /* PR_SetError(xxx); */ err = SVRCORE_System_Error; break; } store->params = PK11_GenerateNewParam(store->mech->type, store->key); if (store->params == 0) { err = SVRCORE_System_Error; break; } /* Compute the size of the encrypted data including necessary padding */ { int blocksize = PK11_GetBlockSize(store->mech->type, 0); store->length = strlen(pin)+1; /* Compute padded size - 0 means stream cipher */ if (blocksize != 0) { store->length += blocksize - (store->length % blocksize); } store->crypt = (unsigned char *)malloc(store->length); if (!store->crypt) { err = SVRCORE_NoMemory_Error; break; } } /* Encrypt */ { unsigned char *plain; PK11Context *ctx; SECStatus rv; int outLen; plain = (unsigned char *)malloc(store->length); if (!plain) { err = SVRCORE_NoMemory_Error; break; } /* Pad with 0 bytes */ memset(plain, 0, store->length); strcpy((char *)plain, pin); ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_ENCRYPT, store->key, store->params); if (!ctx) { err = SVRCORE_System_Error; break; } do { rv = PK11_CipherOp(ctx, store->crypt, &outLen, store->length, plain, store->length); if (rv) break; rv = PK11_Finalize(ctx); } while(0); PK11_DestroyContext(ctx, PR_TRUE); memset(plain, 0, store->length); free(plain); if (rv) err = SVRCORE_System_Error; } } while(0); if (err) { SVRCORE_DestroyPk11PinStore(store); store = 0; } *out = store; return err; }