static isc_boolean_t pkcs11rsa_compare(const dst_key_t *key1, const dst_key_t *key2) { pk11_object_t *rsa1, *rsa2; CK_ATTRIBUTE *attr1, *attr2; rsa1 = key1->keydata.pkey; rsa2 = key2->keydata.pkey; if ((rsa1 == NULL) && (rsa2 == NULL)) return (ISC_TRUE); else if ((rsa1 == NULL) || (rsa2 == NULL)) return (ISC_FALSE); attr1 = pk11_attribute_bytype(rsa1, CKA_MODULUS); attr2 = pk11_attribute_bytype(rsa2, CKA_MODULUS); if ((attr1 == NULL) && (attr2 == NULL)) return (ISC_TRUE); else if ((attr1 == NULL) || (attr2 == NULL) || (attr1->ulValueLen != attr2->ulValueLen) || memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) return (ISC_FALSE); attr1 = pk11_attribute_bytype(rsa1, CKA_PUBLIC_EXPONENT); attr2 = pk11_attribute_bytype(rsa2, CKA_PUBLIC_EXPONENT); if ((attr1 == NULL) && (attr2 == NULL)) return (ISC_TRUE); else if ((attr1 == NULL) || (attr2 == NULL) || (attr1->ulValueLen != attr2->ulValueLen) || memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) return (ISC_FALSE); attr1 = pk11_attribute_bytype(rsa1, CKA_PRIVATE_EXPONENT); attr2 = pk11_attribute_bytype(rsa2, CKA_PRIVATE_EXPONENT); if (((attr1 != NULL) || (attr2 != NULL)) && ((attr1 == NULL) || (attr2 == NULL) || (attr1->ulValueLen != attr2->ulValueLen) || memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))) return (ISC_FALSE); if (!rsa1->ontoken && !rsa2->ontoken) return (ISC_TRUE); else if (rsa1->ontoken || rsa2->ontoken || (rsa1->object != rsa2->object)) return (ISC_FALSE); return (ISC_TRUE); }
static isc_result_t pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label, const char *pin) { CK_RV rv; CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_ATTRIBUTE searchTemplate[] = { { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, { CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) }, { CKA_LABEL, NULL, 0 } }; CK_ULONG cnt; CK_ATTRIBUTE *attr; pk11_object_t *rsa; pk11_context_t *pk11_ctx = NULL; isc_result_t ret; unsigned int i; UNUSED(pin); rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa)); if (rsa == NULL) return (ISC_R_NOMEMORY); memset(rsa, 0, sizeof(*rsa)); rsa->object = CK_INVALID_HANDLE; rsa->ontoken = ISC_TRUE; rsa->reqlogon = ISC_TRUE; key->keydata.pkey = rsa; rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2); if (rsa->repr == NULL) DST_RET(ISC_R_NOMEMORY); memset(rsa->repr, 0, sizeof(*attr) * 2); rsa->attrcnt = 2; attr = rsa->repr; attr[0].type = CKA_MODULUS; attr[1].type = CKA_PUBLIC_EXPONENT; ret = pk11_parse_uri(rsa, label, key->mctx, OP_RSA); if (ret != ISC_R_SUCCESS) goto err; pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, sizeof(*pk11_ctx)); if (pk11_ctx == NULL) DST_RET(ISC_R_NOMEMORY); ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE, rsa->reqlogon, NULL, rsa->slot); if (ret != ISC_R_SUCCESS) goto err; attr = pk11_attribute_bytype(rsa, CKA_LABEL); if (attr == NULL) { attr = pk11_attribute_bytype(rsa, CKA_ID); INSIST(attr != NULL); searchTemplate[3].type = CKA_ID; } searchTemplate[3].pValue = attr->pValue; searchTemplate[3].ulValueLen = attr->ulValueLen; PK11_RET(pkcs_C_FindObjectsInit, (pk11_ctx->session, searchTemplate, (CK_ULONG) 4), DST_R_CRYPTOFAILURE); PK11_RET(pkcs_C_FindObjects, (pk11_ctx->session, &hKey, (CK_ULONG) 1, &cnt), DST_R_CRYPTOFAILURE); (void) pkcs_C_FindObjectsFinal(pk11_ctx->session); if (cnt == 0) DST_RET(ISC_R_NOTFOUND); if (cnt > 1) DST_RET(ISC_R_EXISTS); attr = rsa->repr; PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, hKey, attr, 2), DST_R_CRYPTOFAILURE); for (i = 0; i <= 1; i++) { attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen); if (attr[i].pValue == NULL) DST_RET(ISC_R_NOMEMORY); memset(attr[i].pValue, 0, attr[i].ulValueLen); } PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, hKey, attr, 2), DST_R_CRYPTOFAILURE); keyClass = CKO_PRIVATE_KEY; PK11_RET(pkcs_C_FindObjectsInit, (pk11_ctx->session, searchTemplate, (CK_ULONG) 4), DST_R_CRYPTOFAILURE); PK11_RET(pkcs_C_FindObjects, (pk11_ctx->session, &rsa->object, (CK_ULONG) 1, &cnt), DST_R_CRYPTOFAILURE); (void) pkcs_C_FindObjectsFinal(pk11_ctx->session); if (cnt == 0) DST_RET(ISC_R_NOTFOUND); if (cnt > 1) DST_RET(ISC_R_EXISTS); if (engine != NULL) { key->engine = isc_mem_strdup(key->mctx, engine); if (key->engine == NULL) DST_RET(ISC_R_NOMEMORY); } key->label = isc_mem_strdup(key->mctx, label); if (key->label == NULL) DST_RET(ISC_R_NOMEMORY); attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); INSIST(attr != NULL); if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS) DST_RET(ISC_R_RANGE); attr = pk11_attribute_bytype(rsa, CKA_MODULUS); INSIST(attr != NULL); key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); pk11_return_session(pk11_ctx); memset(pk11_ctx, 0, sizeof(*pk11_ctx)); isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); return (ISC_R_SUCCESS); err: pkcs11rsa_destroy(key); if (pk11_ctx != NULL) { pk11_return_session(pk11_ctx); memset(pk11_ctx, 0, sizeof(*pk11_ctx)); isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); } return (ret); }
static isc_result_t pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t ret; int i; pk11_object_t *rsa; CK_ATTRIBUTE *attr; isc_mem_t *mctx = key->mctx; const char *engine = NULL, *label = NULL; /* read private key file */ ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv); if (ret != ISC_R_SUCCESS) return (ret); if (key->external) { if (priv.nelements != 0) DST_RET(DST_R_INVALIDPRIVATEKEY); if (pub == NULL) DST_RET(DST_R_INVALIDPRIVATEKEY); key->keydata.pkey = pub->keydata.pkey; pub->keydata.pkey = NULL; key->key_size = pub->key_size; dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ISC_R_SUCCESS); } for (i = 0; i < priv.nelements; i++) { switch (priv.elements[i].tag) { case TAG_RSA_ENGINE: engine = (char *)priv.elements[i].data; break; case TAG_RSA_LABEL: label = (char *)priv.elements[i].data; break; default: break; } } rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa)); if (rsa == NULL) DST_RET(ISC_R_NOMEMORY); memset(rsa, 0, sizeof(*rsa)); key->keydata.pkey = rsa; /* Is this key is stored in a HSM? See if we can fetch it. */ if ((label != NULL) || (engine != NULL)) { ret = pkcs11rsa_fetch(key, engine, label, pub); if (ret != ISC_R_SUCCESS) goto err; dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ret); } rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 8); if (rsa->repr == NULL) DST_RET(ISC_R_NOMEMORY); memset(rsa->repr, 0, sizeof(*attr) * 8); rsa->attrcnt = 8; attr = rsa->repr; attr[0].type = CKA_MODULUS; attr[1].type = CKA_PUBLIC_EXPONENT; attr[2].type = CKA_PRIVATE_EXPONENT; attr[3].type = CKA_PRIME_1; attr[4].type = CKA_PRIME_2; attr[5].type = CKA_EXPONENT_1; attr[6].type = CKA_EXPONENT_2; attr[7].type = CKA_COEFFICIENT; for (i = 0; i < priv.nelements; i++) { CK_BYTE *bn; switch (priv.elements[i].tag) { case TAG_RSA_ENGINE: continue; case TAG_RSA_LABEL: continue; default: bn = isc_mem_get(key->mctx, priv.elements[i].length); if (bn == NULL) DST_RET(ISC_R_NOMEMORY); memmove(bn, priv.elements[i].data, priv.elements[i].length); } switch (priv.elements[i].tag) { case TAG_RSA_MODULUS: attr = pk11_attribute_bytype(rsa, CKA_MODULUS); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_RSA_PUBLICEXPONENT: attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_RSA_PRIVATEEXPONENT: attr = pk11_attribute_bytype(rsa, CKA_PRIVATE_EXPONENT); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_RSA_PRIME1: attr = pk11_attribute_bytype(rsa, CKA_PRIME_1); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_RSA_PRIME2: attr = pk11_attribute_bytype(rsa, CKA_PRIME_2); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_RSA_EXPONENT1: attr = pk11_attribute_bytype(rsa, CKA_EXPONENT_1); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_RSA_EXPONENT2: attr = pk11_attribute_bytype(rsa, CKA_EXPONENT_2); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_RSA_COEFFICIENT: attr = pk11_attribute_bytype(rsa, CKA_COEFFICIENT); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; } } if (rsa_check(rsa, pub->keydata.pkey) != ISC_R_SUCCESS) DST_RET(DST_R_INVALIDPRIVATEKEY); attr = pk11_attribute_bytype(rsa, CKA_MODULUS); INSIST(attr != NULL); key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); INSIST(attr != NULL); if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS) DST_RET(ISC_R_RANGE); dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ISC_R_SUCCESS); err: pkcs11rsa_destroy(key); dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ret); }
static isc_result_t rsa_check(pk11_object_t *rsa, pk11_object_t *pubrsa) { CK_ATTRIBUTE *pubattr, *privattr; CK_BYTE *priv_exp = NULL, *priv_mod = NULL; CK_BYTE *pub_exp = NULL, *pub_mod = NULL; unsigned int priv_explen = 0, priv_modlen = 0; unsigned int pub_explen = 0, pub_modlen = 0; REQUIRE(rsa != NULL && pubrsa != NULL); privattr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); INSIST(privattr != NULL); priv_exp = privattr->pValue; priv_explen = privattr->ulValueLen; pubattr = pk11_attribute_bytype(pubrsa, CKA_PUBLIC_EXPONENT); INSIST(pubattr != NULL); pub_exp = pubattr->pValue; pub_explen = pubattr->ulValueLen; if (priv_exp != NULL) { if (priv_explen != pub_explen) return (DST_R_INVALIDPRIVATEKEY); if (memcmp(priv_exp, pub_exp, pub_explen) != 0) return (DST_R_INVALIDPRIVATEKEY); } else { privattr->pValue = pub_exp; privattr->ulValueLen = pub_explen; pubattr->pValue = NULL; pubattr->ulValueLen = 0; } if (privattr->pValue == NULL) return (DST_R_INVALIDPRIVATEKEY); privattr = pk11_attribute_bytype(rsa, CKA_MODULUS); INSIST(privattr != NULL); priv_mod = privattr->pValue; priv_modlen = privattr->ulValueLen; pubattr = pk11_attribute_bytype(pubrsa, CKA_MODULUS); INSIST(pubattr != NULL); pub_mod = pubattr->pValue; pub_modlen = pubattr->ulValueLen; if (priv_mod != NULL) { if (priv_modlen != pub_modlen) return (DST_R_INVALIDPRIVATEKEY); if (memcmp(priv_mod, pub_mod, pub_modlen) != 0) return (DST_R_INVALIDPRIVATEKEY); } else { privattr->pValue = pub_mod; privattr->ulValueLen = pub_modlen; pubattr->pValue = NULL; pubattr->ulValueLen = 0; } if (privattr->pValue == NULL) return (DST_R_INVALIDPRIVATEKEY); return (ISC_R_SUCCESS); }
static isc_result_t pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label, dst_key_t *pub) { CK_RV rv; CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_ATTRIBUTE searchTemplate[] = { { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, { CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) }, { CKA_LABEL, NULL, 0 } }; CK_ULONG cnt; CK_ATTRIBUTE *attr; CK_ATTRIBUTE *pubattr; pk11_object_t *rsa; pk11_object_t *pubrsa; pk11_context_t *pk11_ctx = NULL; isc_result_t ret; if (label == NULL) return (DST_R_NOENGINE); rsa = key->keydata.pkey; pubrsa = pub->keydata.pkey; rsa->object = CK_INVALID_HANDLE; rsa->ontoken = ISC_TRUE; rsa->reqlogon = ISC_TRUE; rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2); if (rsa->repr == NULL) return (ISC_R_NOMEMORY); memset(rsa->repr, 0, sizeof(*attr) * 2); rsa->attrcnt = 2; attr = rsa->repr; attr->type = CKA_MODULUS; pubattr = pk11_attribute_bytype(pubrsa, CKA_MODULUS); attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); if (attr->pValue == NULL) DST_RET(ISC_R_NOMEMORY); memmove(attr->pValue, pubattr->pValue, pubattr->ulValueLen); attr->ulValueLen = pubattr->ulValueLen; attr++; attr->type = CKA_PUBLIC_EXPONENT; pubattr = pk11_attribute_bytype(pubrsa, CKA_PUBLIC_EXPONENT); attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); if (attr->pValue == NULL) DST_RET(ISC_R_NOMEMORY); memmove(attr->pValue, pubattr->pValue, pubattr->ulValueLen); attr->ulValueLen = pubattr->ulValueLen; ret = pk11_parse_uri(rsa, label, key->mctx, OP_RSA); if (ret != ISC_R_SUCCESS) goto err; pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, sizeof(*pk11_ctx)); if (pk11_ctx == NULL) DST_RET(ISC_R_NOMEMORY); ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE, rsa->reqlogon, NULL, rsa->slot); if (ret != ISC_R_SUCCESS) goto err; attr = pk11_attribute_bytype(rsa, CKA_LABEL); if (attr == NULL) { attr = pk11_attribute_bytype(rsa, CKA_ID); INSIST(attr != NULL); searchTemplate[3].type = CKA_ID; } searchTemplate[3].pValue = attr->pValue; searchTemplate[3].ulValueLen = attr->ulValueLen; PK11_RET(pkcs_C_FindObjectsInit, (pk11_ctx->session, searchTemplate, (CK_ULONG) 4), DST_R_CRYPTOFAILURE); PK11_RET(pkcs_C_FindObjects, (pk11_ctx->session, &rsa->object, (CK_ULONG) 1, &cnt), DST_R_CRYPTOFAILURE); (void) pkcs_C_FindObjectsFinal(pk11_ctx->session); if (cnt == 0) DST_RET(ISC_R_NOTFOUND); if (cnt > 1) DST_RET(ISC_R_EXISTS); if (engine != NULL) { key->engine = isc_mem_strdup(key->mctx, engine); if (key->engine == NULL) DST_RET(ISC_R_NOMEMORY); } key->label = isc_mem_strdup(key->mctx, label); if (key->label == NULL) DST_RET(ISC_R_NOMEMORY); pk11_return_session(pk11_ctx); memset(pk11_ctx, 0, sizeof(*pk11_ctx)); isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); attr = pk11_attribute_bytype(rsa, CKA_MODULUS); INSIST(attr != NULL); key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); return (ISC_R_SUCCESS); err: if (pk11_ctx != NULL) { pk11_return_session(pk11_ctx); memset(pk11_ctx, 0, sizeof(*pk11_ctx)); isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); } return (ret); }
static isc_result_t pkcs11gost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t ret; pk11_object_t *gost = NULL; CK_ATTRIBUTE *attr, *pattr; isc_mem_t *mctx = key->mctx; if ((pub == NULL) || (pub->keydata.pkey == NULL)) DST_RET(DST_R_INVALIDPRIVATEKEY); /* read private key file */ ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv); if (ret != ISC_R_SUCCESS) return (ret); if (key->external) { if (priv.nelements != 0) DST_RET(DST_R_INVALIDPRIVATEKEY); key->keydata.pkey = pub->keydata.pkey; pub->keydata.pkey = NULL; key->key_size = pub->key_size; dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ISC_R_SUCCESS); } if (priv.elements[0].tag == TAG_GOST_PRIVASN1) { int adj = (int) priv.elements[0].length - (39 + 32); unsigned char buf[39]; if ((adj > 0) || (adj < -31)) DST_RET(DST_R_INVALIDPRIVATEKEY); memmove(buf, gost_private_der, 39); if (adj != 0) { buf[1] += adj; buf[36] += adj; buf[38] += adj; } if (memcmp(priv.elements[0].data, buf, 39) != 0) DST_RET(DST_R_INVALIDPRIVATEKEY); priv.elements[0].tag = TAG_GOST_PRIVRAW; priv.elements[0].length -= 39; memmove(priv.elements[0].data, priv.elements[0].data + 39, 32 + adj); } gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost)); if (gost == NULL) DST_RET(ISC_R_NOMEMORY); memset(gost, 0, sizeof(*gost)); key->keydata.pkey = gost; gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2); if (gost->repr == NULL) DST_RET(ISC_R_NOMEMORY); memset(gost->repr, 0, sizeof(*attr) * 2); gost->attrcnt = 2; attr = gost->repr; attr->type = CKA_VALUE; pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_VALUE); INSIST(pattr != NULL); attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen); if (attr->pValue == NULL) DST_RET(ISC_R_NOMEMORY); memmove(attr->pValue, pattr->pValue, pattr->ulValueLen); attr->ulValueLen = pattr->ulValueLen; attr++; attr->type = CKA_VALUE2; attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length); if (attr->pValue == NULL) DST_RET(ISC_R_NOMEMORY); memmove(attr->pValue, priv.elements[0].data, priv.elements[0].length); attr->ulValueLen = priv.elements[0].length; dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ISC_R_SUCCESS); err: pkcs11gost_destroy(key); dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ret); }
isc_result_t pk11_parse_uri(pk11_object_t *obj, const char *label, isc_mem_t *mctx, pk11_optype_t optype) { CK_ATTRIBUTE *attr; pk11_token_t *token = NULL; char *uri, *p, *a, *na, *v; size_t len, l; FILE *stream = NULL; char pin[PINLEN + 1]; isc_boolean_t gotpin = ISC_FALSE; isc_result_t ret; /* get values to work on */ len = strlen(label) + 1; uri = isc_mem_get(mctx, len); if (uri == NULL) return (ISC_R_NOMEMORY); memmove(uri, label, len); /* get the URI scheme */ p = strchr(uri, ':'); if (p == NULL) DST_RET(PK11_R_NOPROVIDER); *p++ = '\0'; if (strcmp(uri, "pkcs11") != 0) DST_RET(PK11_R_NOPROVIDER); /* get attributes */ for (na = p; na != NULL;) { a = na; p = strchr(a, ';'); if (p == NULL) { /* last attribute */ na = NULL; } else { *p++ = '\0'; na = p; } p = strchr(a, '='); if (p != NULL) { *p++ = '\0'; v = p; } else v = a; l = 0; v = percent_decode(v, &l); if (v == NULL) DST_RET(PK11_R_NOPROVIDER); if ((a == v) || (strcmp(a, "object") == 0)) { /* object: CKA_LABEL */ attr = pk11_attribute_bytype(obj, CKA_LABEL); if (attr != NULL) DST_RET(PK11_R_NOPROVIDER); attr = push_attribute(obj, mctx, l); if (attr == NULL) DST_RET(ISC_R_NOMEMORY); attr->type = CKA_LABEL; memmove(attr->pValue, v, l); } else if (strcmp(a, "token") == 0) { /* token: CK_TOKEN_INFO label */ if (token == NULL) for (token = ISC_LIST_HEAD(tokens); token != NULL; token = ISC_LIST_NEXT(token, link)) if (pk11strcmp(v, l, token->name, 32)) break; } else if (strcmp(a, "manufacturer") == 0) { /* manufacturer: CK_TOKEN_INFO manufacturerID */ if (token == NULL) for (token = ISC_LIST_HEAD(tokens); token != NULL; token = ISC_LIST_NEXT(token, link)) if (pk11strcmp(v, l, token->manuf, 32)) break; } else if (strcmp(a, "serial") == 0) { /* serial: CK_TOKEN_INFO serialNumber */ if (token == NULL) for (token = ISC_LIST_HEAD(tokens); token != NULL; token = ISC_LIST_NEXT(token, link)) if (pk11strcmp(v, l, token->serial, 16)) break; } else if (strcmp(a, "model") == 0) { /* model: CK_TOKEN_INFO model */ if (token == NULL) for (token = ISC_LIST_HEAD(tokens); token != NULL; token = ISC_LIST_NEXT(token, link)) if (pk11strcmp(v, l, token->model, 16)) break; } else if (strcmp(a, "library-manufacturer") == 0) { /* ignored */ } else if (strcmp(a, "library-description") == 0) { /* ignored */ } else if (strcmp(a, "library-version") == 0) { /* ignored */ } else if (strcmp(a, "object-type") == 0) { /* object-type: CKA_CLASS */ /* only private makes sense */ if (strcmp(v, "private") != 0) DST_RET(PK11_R_NOPROVIDER); } else if (strcmp(a, "id") == 0) { /* id: CKA_ID */ attr = pk11_attribute_bytype(obj, CKA_ID); if (attr != NULL) DST_RET(PK11_R_NOPROVIDER); attr = push_attribute(obj, mctx, l); if (attr == NULL) DST_RET(ISC_R_NOMEMORY); attr->type = CKA_ID; memmove(attr->pValue, v, l); } else if (strcmp(a, "pin-source") == 0) { /* pin-source: PIN */ ret = isc_stdio_open(v, "r", &stream); if (ret != ISC_R_SUCCESS) goto err; memset(pin, 0, PINLEN + 1); ret = isc_stdio_read(pin, 1, PINLEN + 1, stream, &l); if ((ret != ISC_R_SUCCESS) && (ret != ISC_R_EOF)) goto err; if (l > PINLEN) DST_RET(ISC_R_RANGE); ret = isc_stdio_close(stream); stream = NULL; if (ret != ISC_R_SUCCESS) goto err; gotpin = ISC_TRUE; } else DST_RET(PK11_R_NOPROVIDER); } if ((pk11_attribute_bytype(obj, CKA_LABEL) == NULL) && (pk11_attribute_bytype(obj, CKA_ID) == NULL)) DST_RET(ISC_R_NOTFOUND); if (token == NULL) { if (optype == OP_RSA) token = best_rsa_token; else if (optype == OP_DSA) token = best_dsa_token; else if (optype == OP_DH) token = best_dh_token; else if (optype == OP_EC) token = best_ec_token; } if (token == NULL) DST_RET(ISC_R_NOTFOUND); obj->slot = token->slotid; if (gotpin) { memmove(token->pin, pin, PINLEN + 1); obj->reqlogon = ISC_TRUE; } ret = ISC_R_SUCCESS; err: if (stream != NULL) (void) isc_stdio_close(stream); isc_mem_put(mctx, uri, len); return (ret); }
static isc_result_t pkcs11ecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t ret; pk11_object_t *ec = NULL; CK_ATTRIBUTE *attr, *pattr; isc_mem_t *mctx = key->mctx; unsigned int i; const char *engine = NULL, *label = NULL; REQUIRE(key->key_alg == DST_ALG_ECDSA256 || key->key_alg == DST_ALG_ECDSA384); if ((pub == NULL) || (pub->keydata.pkey == NULL)) DST_RET(DST_R_INVALIDPRIVATEKEY); /* read private key file */ ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv); if (ret != ISC_R_SUCCESS) return (ret); if (key->external) { if (priv.nelements != 0) DST_RET(DST_R_INVALIDPRIVATEKEY); key->keydata.pkey = pub->keydata.pkey; pub->keydata.pkey = NULL; key->key_size = pub->key_size; dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ISC_R_SUCCESS); } for (i = 0; i < priv.nelements; i++) { switch (priv.elements[i].tag) { case TAG_ECDSA_ENGINE: engine = (char *)priv.elements[i].data; break; case TAG_ECDSA_LABEL: label = (char *)priv.elements[i].data; break; default: break; } } ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec)); if (ec == NULL) DST_RET(ISC_R_NOMEMORY); memset(ec, 0, sizeof(*ec)); key->keydata.pkey = ec; /* Is this key is stored in a HSM? See if we can fetch it. */ if ((label != NULL) || (engine != NULL)) { ret = pkcs11ecdsa_fetch(key, engine, label, pub); if (ret != ISC_R_SUCCESS) goto err; dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ret); } ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3); if (ec->repr == NULL) DST_RET(ISC_R_NOMEMORY); memset(ec->repr, 0, sizeof(*attr) * 3); ec->attrcnt = 3; attr = ec->repr; attr->type = CKA_EC_PARAMS; pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_PARAMS); INSIST(pattr != NULL); attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen); if (attr->pValue == NULL) DST_RET(ISC_R_NOMEMORY); memmove(attr->pValue, pattr->pValue, pattr->ulValueLen); attr->ulValueLen = pattr->ulValueLen; attr++; attr->type = CKA_EC_POINT; pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_POINT); INSIST(pattr != NULL); attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen); if (attr->pValue == NULL) DST_RET(ISC_R_NOMEMORY); memmove(attr->pValue, pattr->pValue, pattr->ulValueLen); attr->ulValueLen = pattr->ulValueLen; attr++; attr->type = CKA_VALUE; attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length); if (attr->pValue == NULL) DST_RET(ISC_R_NOMEMORY); memmove(attr->pValue, priv.elements[0].data, priv.elements[0].length); attr->ulValueLen = priv.elements[0].length; dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); if (key->key_alg == DST_ALG_ECDSA256) key->key_size = DNS_KEY_ECDSA256SIZE * 4; else key->key_size = DNS_KEY_ECDSA384SIZE * 4; return (ISC_R_SUCCESS); err: pkcs11ecdsa_destroy(key); dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ret); }
static isc_result_t pkcs11dh_loadpriv(const dst_key_t *key, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey) { CK_RV rv; CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_DH; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, { CKA_DERIVE, &truevalue, (CK_ULONG) sizeof(truevalue) }, { CKA_PRIME, NULL, 0 }, { CKA_BASE, NULL, 0 }, { CKA_VALUE, NULL, 0 } }; CK_ATTRIBUTE *attr; const pk11_object_t *priv; isc_result_t ret; unsigned int i; priv = key->keydata.pkey; if ((priv->object != CK_INVALID_HANDLE) && priv->ontoken) { *hKey = priv->object; return (ISC_R_SUCCESS); } attr = pk11_attribute_bytype(priv, CKA_PRIME); if (attr == NULL) return (DST_R_INVALIDPRIVATEKEY); keyTemplate[6].pValue = isc_mem_get(key->mctx, attr->ulValueLen); if (keyTemplate[6].pValue == NULL) DST_RET(ISC_R_NOMEMORY); memmove(keyTemplate[6].pValue, attr->pValue, attr->ulValueLen); keyTemplate[6].ulValueLen = attr->ulValueLen; attr = pk11_attribute_bytype(priv, CKA_BASE); if (attr == NULL) DST_RET(DST_R_INVALIDPRIVATEKEY); keyTemplate[7].pValue = isc_mem_get(key->mctx, attr->ulValueLen); if (keyTemplate[7].pValue == NULL) DST_RET(ISC_R_NOMEMORY); memmove(keyTemplate[7].pValue, attr->pValue, attr->ulValueLen); keyTemplate[7].ulValueLen = attr->ulValueLen; attr = pk11_attribute_bytype(priv, CKA_VALUE2); if (attr == NULL) DST_RET(DST_R_INVALIDPRIVATEKEY); keyTemplate[8].pValue = isc_mem_get(key->mctx, attr->ulValueLen); if (keyTemplate[8].pValue == NULL) DST_RET(ISC_R_NOMEMORY); memmove(keyTemplate[8].pValue, attr->pValue, attr->ulValueLen); keyTemplate[8].ulValueLen = attr->ulValueLen; PK11_CALL(pkcs_C_CreateObject, (session, keyTemplate, (CK_ULONG) 9, hKey), DST_R_COMPUTESECRETFAILURE); if (rv == CKR_OK) ret = ISC_R_SUCCESS; err: for (i = 6; i <= 8; i++) if (keyTemplate[i].pValue != NULL) { memset(keyTemplate[i].pValue, 0, keyTemplate[i].ulValueLen); isc_mem_put(key->mctx, keyTemplate[i].pValue, keyTemplate[i].ulValueLen); } return (ret); }
static isc_result_t pkcs11dh_computesecret(const dst_key_t *pub, const dst_key_t *priv, isc_buffer_t *secret) { CK_RV rv; CK_MECHANISM mech = { CKM_DH_PKCS_DERIVE, NULL, 0 }; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_OBJECT_HANDLE hDerived = CK_INVALID_HANDLE; CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; CK_ATTRIBUTE *attr; CK_ULONG secLen; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, { CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) }, { CKA_VALUE_LEN, &secLen, (CK_ULONG) sizeof(secLen) } }; CK_ATTRIBUTE valTemplate[] = { { CKA_VALUE, NULL, 0 } }; CK_BYTE *secValue; pk11_context_t ctx; isc_result_t ret; unsigned int i; isc_region_t r; REQUIRE(pub->keydata.pkey != NULL); REQUIRE(priv->keydata.pkey != NULL); REQUIRE(priv->keydata.pkey->repr != NULL); attr = pk11_attribute_bytype(pub->keydata.pkey, CKA_PRIME); if (attr == NULL) return (DST_R_INVALIDPUBLICKEY); REQUIRE(attr != NULL); secLen = attr->ulValueLen; attr = pk11_attribute_bytype(pub->keydata.pkey, CKA_VALUE); if (attr == NULL) return (DST_R_INVALIDPUBLICKEY); ret = pk11_get_session(&ctx, OP_DH, ISC_TRUE, ISC_FALSE, ISC_FALSE, NULL, pk11_get_best_token(OP_DH)); if (ret != ISC_R_SUCCESS) return (ret); mech.ulParameterLen = attr->ulValueLen; mech.pParameter = isc_mem_get(pub->mctx, mech.ulParameterLen); if (mech.pParameter == NULL) DST_RET(ISC_R_NOMEMORY); memmove(mech.pParameter, attr->pValue, mech.ulParameterLen); ret = pkcs11dh_loadpriv(priv, ctx.session, &hKey); if (ret != ISC_R_SUCCESS) goto err; PK11_RET(pkcs_C_DeriveKey, (ctx.session, &mech, hKey, keyTemplate, (CK_ULONG) 6, &hDerived), DST_R_COMPUTESECRETFAILURE); attr = valTemplate; PK11_RET(pkcs_C_GetAttributeValue, (ctx.session, hDerived, attr, (CK_ULONG) 1), DST_R_CRYPTOFAILURE); attr->pValue = isc_mem_get(pub->mctx, attr->ulValueLen); if (attr->pValue == NULL) DST_RET(ISC_R_NOMEMORY); memset(attr->pValue, 0, attr->ulValueLen); PK11_RET(pkcs_C_GetAttributeValue, (ctx.session, hDerived, attr, (CK_ULONG) 1), DST_R_CRYPTOFAILURE); /* strip leading zeros */ secValue = (CK_BYTE_PTR) attr->pValue; for (i = 0; i < attr->ulValueLen; i++) if (secValue[i] != 0) break; isc_buffer_availableregion(secret, &r); if (r.length < attr->ulValueLen - i) DST_RET(ISC_R_NOSPACE); memmove(r.base, secValue + i, attr->ulValueLen - i); isc_buffer_add(secret, attr->ulValueLen - i); ret = ISC_R_SUCCESS; err: if (hDerived != CK_INVALID_HANDLE) (void) pkcs_C_DestroyObject(ctx.session, hDerived); if (valTemplate[0].pValue != NULL) { memset(valTemplate[0].pValue, 0, valTemplate[0].ulValueLen); isc_mem_put(pub->mctx, valTemplate[0].pValue, valTemplate[0].ulValueLen); } if ((hKey != CK_INVALID_HANDLE) && !priv->keydata.pkey->ontoken) (void) pkcs_C_DestroyObject(ctx.session, hKey); if (mech.pParameter != NULL) { memset(mech.pParameter, 0, mech.ulParameterLen); isc_mem_put(pub->mctx, mech.pParameter, mech.ulParameterLen); } pk11_return_session(&ctx); return (ret); }
static isc_result_t pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t ret; int i; pk11_object_t *dsa = NULL; CK_ATTRIBUTE *attr; isc_mem_t *mctx = key->mctx; /* read private key file */ ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv); if (ret != ISC_R_SUCCESS) return (ret); if (key->external) { if (priv.nelements != 0) DST_RET(DST_R_INVALIDPRIVATEKEY); if (pub == NULL) DST_RET(DST_R_INVALIDPRIVATEKEY); key->keydata.pkey = pub->keydata.pkey; pub->keydata.pkey = NULL; key->key_size = pub->key_size; dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ISC_R_SUCCESS); } dsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dsa)); if (dsa == NULL) DST_RET(ISC_R_NOMEMORY); memset(dsa, 0, sizeof(*dsa)); key->keydata.pkey = dsa; dsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 5); if (dsa->repr == NULL) DST_RET(ISC_R_NOMEMORY); memset(dsa->repr, 0, sizeof(*attr) * 5); dsa->attrcnt = 5; attr = dsa->repr; attr[0].type = CKA_PRIME; attr[1].type = CKA_SUBPRIME; attr[2].type = CKA_BASE; attr[3].type = CKA_VALUE; attr[4].type = CKA_VALUE2; for (i = 0; i < priv.nelements; i++) { CK_BYTE *bn; bn = isc_mem_get(key->mctx, priv.elements[i].length); if (bn == NULL) DST_RET(ISC_R_NOMEMORY); memmove(bn, priv.elements[i].data, priv.elements[i].length); switch (priv.elements[i].tag) { case TAG_DSA_PRIME: attr = pk11_attribute_bytype(dsa, CKA_PRIME); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_DSA_SUBPRIME: attr = pk11_attribute_bytype(dsa, CKA_SUBPRIME); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_DSA_BASE: attr = pk11_attribute_bytype(dsa, CKA_BASE); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_DSA_PRIVATE: attr = pk11_attribute_bytype(dsa, CKA_VALUE2); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; case TAG_DSA_PUBLIC: attr = pk11_attribute_bytype(dsa, CKA_VALUE); INSIST(attr != NULL); attr->pValue = bn; attr->ulValueLen = priv.elements[i].length; break; } } dst__privstruct_free(&priv, mctx); attr = pk11_attribute_bytype(dsa, CKA_PRIME); INSIST(attr != NULL); key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); return (ISC_R_SUCCESS); err: pkcs11dsa_destroy(key); dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ret); }
static isc_boolean_t pkcs11dsa_compare(const dst_key_t *key1, const dst_key_t *key2) { pk11_object_t *dsa1, *dsa2; CK_ATTRIBUTE *attr1, *attr2; dsa1 = key1->keydata.pkey; dsa2 = key2->keydata.pkey; if ((dsa1 == NULL) && (dsa2 == NULL)) return (ISC_TRUE); else if ((dsa1 == NULL) || (dsa2 == NULL)) return (ISC_FALSE); attr1 = pk11_attribute_bytype(dsa1, CKA_PRIME); attr2 = pk11_attribute_bytype(dsa2, CKA_PRIME); if ((attr1 == NULL) && (attr2 == NULL)) return (ISC_TRUE); else if ((attr1 == NULL) || (attr2 == NULL) || (attr1->ulValueLen != attr2->ulValueLen) || memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) return (ISC_FALSE); attr1 = pk11_attribute_bytype(dsa1, CKA_SUBPRIME); attr2 = pk11_attribute_bytype(dsa2, CKA_SUBPRIME); if ((attr1 == NULL) && (attr2 == NULL)) return (ISC_TRUE); else if ((attr1 == NULL) || (attr2 == NULL) || (attr1->ulValueLen != attr2->ulValueLen) || memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) return (ISC_FALSE); attr1 = pk11_attribute_bytype(dsa1, CKA_BASE); attr2 = pk11_attribute_bytype(dsa2, CKA_BASE); if ((attr1 == NULL) && (attr2 == NULL)) return (ISC_TRUE); else if ((attr1 == NULL) || (attr2 == NULL) || (attr1->ulValueLen != attr2->ulValueLen) || memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) return (ISC_FALSE); attr1 = pk11_attribute_bytype(dsa1, CKA_VALUE); attr2 = pk11_attribute_bytype(dsa2, CKA_VALUE); if ((attr1 == NULL) && (attr2 == NULL)) return (ISC_TRUE); else if ((attr1 == NULL) || (attr2 == NULL) || (attr1->ulValueLen != attr2->ulValueLen) || memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) return (ISC_FALSE); attr1 = pk11_attribute_bytype(dsa1, CKA_VALUE2); attr2 = pk11_attribute_bytype(dsa2, CKA_VALUE2); if (((attr1 != NULL) || (attr2 != NULL)) && ((attr1 == NULL) || (attr2 == NULL) || (attr1->ulValueLen != attr2->ulValueLen) || memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))) return (ISC_FALSE); if (!dsa1->ontoken && !dsa2->ontoken) return (ISC_TRUE); else if (dsa1->ontoken || dsa2->ontoken || (dsa1->object != dsa2->object)) return (ISC_FALSE); return (ISC_TRUE); }