/* * The Initial Developer of the Original Code is International * Business Machines Corporation. Portions created by IBM * Corporation are Copyright (C) 2005 International Business * Machines Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the Common Public License as published by * IBM Corporation; either version 1 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Common Public License for more details. * * You should have received a copy of the Common Public License * along with this program; if not, a copy can be viewed at * http://www.opensource.org/licenses/cpl1.0.php. */ /* (C) COPYRIGHT International Business Machines Corp. 2001, 2002, 2005 */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "tpmtok_int.h" static CK_BBOOL true = TRUE, false = FALSE; static CK_RV key_mgr_get_private_key_type( CK_BYTE *keydata, CK_ULONG keylen, CK_KEY_TYPE *keytype) { CK_BYTE *alg = NULL; CK_BYTE *priv_key = NULL; CK_ULONG alg_len; CK_RV rc; rc = ber_decode_PrivateKeyInfo(keydata, keylen, &alg, &alg_len, &priv_key); if (rc != CKR_OK) { return (rc); } if (alg_len >= ber_rsaEncryptionLen) { if (memcmp(alg, ber_rsaEncryption, ber_rsaEncryptionLen) == 0) { *keytype = CKK_RSA; return (CKR_OK); } } return (CKR_TEMPLATE_INCOMPLETE); } CK_RV key_mgr_generate_key_pair(SESSION * sess, CK_MECHANISM * mech, CK_ATTRIBUTE * publ_tmpl, CK_ULONG publ_count, CK_ATTRIBUTE * priv_tmpl, CK_ULONG priv_count, CK_OBJECT_HANDLE * publ_key_handle, CK_OBJECT_HANDLE * priv_key_handle) { OBJECT * publ_key_obj = NULL; OBJECT * priv_key_obj = NULL; CK_ATTRIBUTE * attr = NULL; CK_ATTRIBUTE * new_attr = NULL; CK_ULONG i, keyclass, subclass = 0; CK_BBOOL flag; CK_RV rc; if (! sess || ! mech || ! publ_key_handle || ! priv_key_handle) { return (CKR_FUNCTION_FAILED); } if (! publ_tmpl && (publ_count != 0)) { return (CKR_FUNCTION_FAILED); } if (! priv_tmpl && (priv_count != 0)) { return (CKR_FUNCTION_FAILED); } for (i = 0; i < publ_count; i++) { if (publ_tmpl[i].type == CKA_CLASS) { keyclass = *(CK_OBJECT_CLASS *)publ_tmpl[i].pValue; if (keyclass != CKO_PUBLIC_KEY) { return (CKR_TEMPLATE_INCONSISTENT); } } if (publ_tmpl[i].type == CKA_KEY_TYPE) subclass = *(CK_ULONG *)publ_tmpl[i].pValue; } for (i = 0; i < priv_count; i++) { if (priv_tmpl[i].type == CKA_CLASS) { keyclass = *(CK_OBJECT_CLASS *)priv_tmpl[i].pValue; if (keyclass != CKO_PRIVATE_KEY) { return (CKR_TEMPLATE_INCONSISTENT); } } if (priv_tmpl[i].type == CKA_KEY_TYPE) { CK_ULONG temp = *(CK_ULONG *)priv_tmpl[i].pValue; if (temp != subclass) { return (CKR_TEMPLATE_INCONSISTENT); } } } switch (mech->mechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: if (subclass != 0 && subclass != CKK_RSA) { return (CKR_TEMPLATE_INCONSISTENT); } subclass = CKK_RSA; break; default: return (CKR_MECHANISM_INVALID); } rc = object_mgr_create_skel(sess, publ_tmpl, publ_count, MODE_KEYGEN, CKO_PUBLIC_KEY, subclass, &publ_key_obj); if (rc != CKR_OK) { goto error; } rc = object_mgr_create_skel(sess, priv_tmpl, priv_count, MODE_KEYGEN, CKO_PRIVATE_KEY, subclass, &priv_key_obj); if (rc != CKR_OK) { goto error; } switch (mech->mechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: rc = ckm_rsa_key_pair_gen( sess->hContext, publ_key_obj->template, priv_key_obj->template); break; default: rc = CKR_MECHANISM_INVALID; break; } if (rc != CKR_OK) { goto error; } /* * we can now set CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE * to their appropriate values. this only applies to CKO_SECRET_KEY * and CKO_PRIVATE_KEY objects */ flag = template_attribute_find(priv_key_obj->template, CKA_SENSITIVE, &attr); if (flag == TRUE) { flag = *(CK_BBOOL *)attr->pValue; rc = build_attribute(CKA_ALWAYS_SENSITIVE, &flag, sizeof (CK_BBOOL), &new_attr); if (rc != CKR_OK) { goto error; } (void) template_update_attribute(priv_key_obj->template, new_attr); } else { rc = CKR_FUNCTION_FAILED; goto error; } flag = template_attribute_find(priv_key_obj->template, CKA_EXTRACTABLE, &attr); if (flag == TRUE) { flag = *(CK_BBOOL *)attr->pValue; rc = build_attribute(CKA_NEVER_EXTRACTABLE, &true, sizeof (CK_BBOOL), &new_attr); if (rc != CKR_OK) { goto error; } if (flag == TRUE) *(CK_BBOOL *)new_attr->pValue = false; (void) template_update_attribute(priv_key_obj->template, new_attr); } else { rc = CKR_FUNCTION_FAILED; goto error; } rc = object_mgr_create_final(sess, publ_key_obj, publ_key_handle); if (rc != CKR_OK) { goto error; } rc = object_mgr_create_final(sess, priv_key_obj, priv_key_handle); if (rc != CKR_OK) { (void) object_mgr_destroy_object(sess, *publ_key_handle); publ_key_obj = NULL; goto error; } return (rc); error: if (publ_key_obj) (void) object_free(publ_key_obj); if (priv_key_obj) (void) object_free(priv_key_obj); *publ_key_handle = 0; *priv_key_handle = 0; return (rc); } CK_RV key_mgr_wrap_key(SESSION * sess, CK_BBOOL length_only, CK_MECHANISM * mech, CK_OBJECT_HANDLE h_wrapping_key, CK_OBJECT_HANDLE h_key, CK_BYTE * wrapped_key, CK_ULONG * wrapped_key_len) { ENCR_DECR_CONTEXT * ctx = NULL; OBJECT * key1_obj = NULL; OBJECT * key2_obj = NULL; CK_ATTRIBUTE * attr = NULL; CK_BYTE * data = NULL; CK_ULONG data_len; CK_OBJECT_CLASS class; CK_KEY_TYPE keytype; CK_BBOOL flag; CK_RV rc; if (! sess || ! wrapped_key_len) { return (CKR_FUNCTION_FAILED); } rc = object_mgr_find_in_map1(sess->hContext, h_wrapping_key, &key1_obj); if (rc != CKR_OK) { return (CKR_WRAPPING_KEY_HANDLE_INVALID); } rc = object_mgr_find_in_map1(sess->hContext, h_key, &key2_obj); if (rc != CKR_OK) { return (CKR_KEY_HANDLE_INVALID); } rc = template_attribute_find(key2_obj->template, CKA_EXTRACTABLE, &attr); if (rc == FALSE) { return (CKR_KEY_NOT_WRAPPABLE); } else { flag = *(CK_BBOOL *)attr->pValue; if (flag == FALSE) { return (CKR_KEY_NOT_WRAPPABLE); } } rc = template_attribute_find(key2_obj->template, CKA_CLASS, &attr); if (rc == FALSE) { return (CKR_KEY_NOT_WRAPPABLE); } else class = *(CK_OBJECT_CLASS *)attr->pValue; switch (mech->mechanism) { case CKM_RSA_PKCS: if (class != CKO_SECRET_KEY) { return (CKR_KEY_NOT_WRAPPABLE); } break; default: return (CKR_KEY_NOT_WRAPPABLE); } rc = template_attribute_find(key2_obj->template, CKA_KEY_TYPE, &attr); if (rc == FALSE) return (CKR_KEY_NOT_WRAPPABLE); else keytype = *(CK_KEY_TYPE *)attr->pValue; switch (keytype) { case CKK_RSA: rc = rsa_priv_wrap_get_data(key2_obj->template, length_only, &data, &data_len); if (rc != CKR_OK) { return (rc); } break; case CKK_GENERIC_SECRET: rc = generic_secret_wrap_get_data(key2_obj->template, length_only, &data, &data_len); if (rc != CKR_OK) { return (rc); } break; default: return (CKR_KEY_NOT_WRAPPABLE); } switch (mech->mechanism) { case CKM_RSA_PKCS: break; default: return (CKR_KEY_NOT_WRAPPABLE); } ctx = (ENCR_DECR_CONTEXT *)malloc(sizeof (ENCR_DECR_CONTEXT)); if (! ctx) { return (CKR_HOST_MEMORY); } (void) memset(ctx, 0x0, sizeof (ENCR_DECR_CONTEXT)); rc = encr_mgr_init(sess, ctx, OP_WRAP, mech, h_wrapping_key); if (rc != CKR_OK) { return (rc); } rc = encr_mgr_encrypt(sess, length_only, ctx, data, data_len, wrapped_key, wrapped_key_len); if (data != NULL) { free(data); } (void) encr_mgr_cleanup(ctx); free(ctx); return (rc); } CK_RV key_mgr_unwrap_key(SESSION * sess, CK_MECHANISM * mech, CK_ATTRIBUTE * attributes, CK_ULONG attrib_count, CK_BYTE * wrapped_key, CK_ULONG wrapped_key_len, CK_OBJECT_HANDLE h_unwrapping_key, CK_OBJECT_HANDLE * h_unwrapped_key) { ENCR_DECR_CONTEXT * ctx = NULL; OBJECT * key_obj = NULL; CK_BYTE * data = NULL; CK_ULONG data_len; CK_ULONG keyclass, keytype; CK_ULONG i; CK_BBOOL found_class, found_type, fromend; CK_RV rc; if (! sess || ! wrapped_key || ! h_unwrapped_key) { return (CKR_FUNCTION_FAILED); } rc = object_mgr_find_in_map1(sess->hContext, h_unwrapping_key, &key_obj); if (rc != CKR_OK) { return (CKR_WRAPPING_KEY_HANDLE_INVALID); } found_class = FALSE; found_type = FALSE; switch (mech->mechanism) { case CKM_RSA_PKCS: keyclass = CKO_SECRET_KEY; found_class = TRUE; break; } for (i = 0; i < attrib_count; i++) { switch (attributes[i].type) { case CKA_CLASS: keyclass = *(CK_OBJECT_CLASS *)attributes[i].pValue; found_class = TRUE; break; case CKA_KEY_TYPE: keytype = *(CK_KEY_TYPE *)attributes[i].pValue; found_type = TRUE; break; } } if (found_class == FALSE || (found_type == FALSE && keyclass != CKO_PRIVATE_KEY)) { return (CKR_TEMPLATE_INCOMPLETE); } switch (mech->mechanism) { case CKM_RSA_PKCS: if (keyclass != CKO_SECRET_KEY) { return (CKR_TEMPLATE_INCONSISTENT); } break; default: return (CKR_MECHANISM_INVALID); } ctx = (ENCR_DECR_CONTEXT *)malloc(sizeof (ENCR_DECR_CONTEXT)); if (! ctx) { return (CKR_HOST_MEMORY); } (void) memset(ctx, 0x0, sizeof (ENCR_DECR_CONTEXT)); rc = decr_mgr_init(sess, ctx, OP_UNWRAP, mech, h_unwrapping_key); if (rc != CKR_OK) return (rc); rc = decr_mgr_decrypt(sess, TRUE, ctx, wrapped_key, wrapped_key_len, data, &data_len); if (rc != CKR_OK) { goto error; } data = (CK_BYTE *)malloc(data_len); if (! data) { rc = CKR_HOST_MEMORY; goto error; } rc = decr_mgr_decrypt(sess, FALSE, ctx, wrapped_key, wrapped_key_len, data, &data_len); (void) decr_mgr_cleanup(ctx); free(ctx); if (rc != CKR_OK) { goto error; } /* * if we use X.509, the data will be padded from the front with zeros. * PKCS #11 specifies that for this mechanism, CK_VALUE is to be read * from the end of the data. * * Note: the PKCS #11 reference implementation gets this wrong. */ if (mech->mechanism == CKM_RSA_X_509) fromend = TRUE; else fromend = FALSE; if (keyclass == CKO_PRIVATE_KEY) { rc = key_mgr_get_private_key_type(data, data_len, &keytype); if (rc != CKR_OK) { goto error; } } rc = object_mgr_create_skel(sess, attributes, attrib_count, MODE_UNWRAP, keyclass, keytype, &key_obj); if (rc != CKR_OK) { goto error; } switch (keyclass) { case CKO_SECRET_KEY: rc = secret_key_unwrap(key_obj->template, keytype, data, data_len, fromend); break; case CKO_PRIVATE_KEY: rc = priv_key_unwrap(key_obj->template, keytype, data, data_len); break; default: rc = CKR_WRAPPED_KEY_INVALID; break; } if (rc != CKR_OK) { goto error; } rc = object_mgr_create_final(sess, key_obj, h_unwrapped_key); if (rc != CKR_OK) { goto error; } if (data) free(data); return (rc); error: if (key_obj) (void) object_free(key_obj); if (data) free(data); return (rc); }