int sc_pkcs15_convert_pubkey(struct sc_pkcs15_pubkey *pkcs15_key, void *evp_key) { #ifdef ENABLE_OPENSSL EVP_PKEY *pk = (EVP_PKEY *)evp_key; switch (pk->type) { case EVP_PKEY_RSA: { struct sc_pkcs15_pubkey_rsa *dst = &pkcs15_key->u.rsa; RSA *src = EVP_PKEY_get1_RSA(pk); pkcs15_key->algorithm = SC_ALGORITHM_RSA; if (!sc_pkcs15_convert_bignum(&dst->modulus, src->n) || !sc_pkcs15_convert_bignum(&dst->exponent, src->e)) return SC_ERROR_INVALID_DATA; RSA_free(src); break; } case EVP_PKEY_DSA: { struct sc_pkcs15_pubkey_dsa *dst = &pkcs15_key->u.dsa; DSA *src = EVP_PKEY_get1_DSA(pk); pkcs15_key->algorithm = SC_ALGORITHM_DSA; sc_pkcs15_convert_bignum(&dst->pub, src->pub_key); sc_pkcs15_convert_bignum(&dst->p, src->p); sc_pkcs15_convert_bignum(&dst->q, src->q); sc_pkcs15_convert_bignum(&dst->g, src->g); DSA_free(src); break; } #if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) case NID_id_GostR3410_2001: { struct sc_pkcs15_pubkey_gostr3410 *dst = &pkcs15_key->u.gostr3410; EC_KEY *eckey = EVP_PKEY_get0(pk); const EC_POINT *point; BIGNUM *X, *Y; int r = 0; assert(eckey); point = EC_KEY_get0_public_key(eckey); if (!point) return SC_ERROR_INTERNAL; X = BN_new(); Y = BN_new(); if (X && Y && EC_KEY_get0_group(eckey)) r = EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(eckey), point, X, Y, NULL); if (r == 1) { dst->xy.len = BN_num_bytes(X) + BN_num_bytes(Y); dst->xy.data = malloc(dst->xy.len); if (dst->xy.data) { BN_bn2bin(Y, dst->xy.data); BN_bn2bin(X, dst->xy.data + BN_num_bytes(Y)); r = sc_mem_reverse(dst->xy.data, dst->xy.len); if (!r) r = 1; pkcs15_key->algorithm = SC_ALGORITHM_GOSTR3410; } else r = -1; } BN_free(X); BN_free(Y); if (r != 1) return SC_ERROR_INTERNAL; break; } case EVP_PKEY_EC: { struct sc_pkcs15_pubkey_ec *dst = &pkcs15_key->u.ec; EC_KEY *src = NULL; const EC_GROUP *grp = NULL; unsigned char buf[255]; size_t buflen = 255; int nid; src = EVP_PKEY_get0(pk); assert(src); assert(EC_KEY_get0_public_key(src)); pkcs15_key->algorithm = SC_ALGORITHM_EC; grp = EC_KEY_get0_group(src); if(grp == 0) return SC_ERROR_INCOMPATIBLE_KEY; /* Decode EC_POINT from a octet string */ buflen = EC_POINT_point2oct(grp, (const EC_POINT *) EC_KEY_get0_public_key(src), POINT_CONVERSION_UNCOMPRESSED, buf, buflen, NULL); /* get curve name */ nid = EC_GROUP_get_curve_name(grp); if(nid != 0) { const char *name = OBJ_nid2sn(nid); if(sizeof(name) > 0) dst->params.named_curve = strdup(name); } /* copy the public key */ if (buflen > 0) { dst->ecpointQ.value = malloc(buflen); memcpy(dst->ecpointQ.value, buf, buflen); dst->ecpointQ.len = buflen; /* calculate the field length */ dst->params.field_length = (buflen - 1) / 2 * 8; } else return SC_ERROR_INCOMPATIBLE_KEY; break; } #endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) */ default: return SC_ERROR_NOT_SUPPORTED; } return SC_SUCCESS; #else return SC_ERROR_NOT_IMPLEMENTED; #endif }
LIBOPENSC_API int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *obj, unsigned long flags, const u8 *in, size_t inlen, u8 *out, size_t outlen) { sc_context_t *ctx = p15card->card->ctx; int r; sc_security_env_t senv; sc_algorithm_info_t *alg_info; const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data; u8 buf[1024], *tmp; size_t modlen; unsigned long pad_flags = 0, sec_flags = 0; LOG_FUNC_CALLED(ctx); sc_log(ctx, "security operation flags 0x%X", flags); memset(&senv, 0, sizeof(senv)); /* Card driver should have the access to supported algorithms from 'tokenInfo'. So that * it can get value of card specific 'AlgorithmInfo::algRef'. */ memcpy(&senv.supported_algos, &p15card->tokeninfo->supported_algos, sizeof(senv.supported_algos)); if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) != SC_PKCS15_TYPE_PRKEY) LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This is not a private key"); /* If the key is not native, we can't operate with it. */ if (!prkey->native) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "This key is not native, cannot operate with it"); if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER| SC_PKCS15_PRKEY_USAGE_NONREPUDIATION))) LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for signing"); switch (obj->type) { case SC_PKCS15_TYPE_PRKEY_RSA: modlen = prkey->modulus_length / 8; alg_info = sc_card_find_rsa_alg(p15card->card, prkey->modulus_length); if (alg_info == NULL) { sc_log(ctx, "Card does not support RSA with key length %d", prkey->modulus_length); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); } senv.flags |= SC_SEC_ENV_ALG_PRESENT; senv.algorithm = SC_ALGORITHM_RSA; break; case SC_PKCS15_TYPE_PRKEY_GOSTR3410: modlen = (prkey->modulus_length + 7) / 8 * 2; alg_info = sc_card_find_gostr3410_alg(p15card->card, prkey->modulus_length); if (alg_info == NULL) { sc_log(ctx, "Card does not support GOSTR3410 with key length %d", prkey->modulus_length); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); } senv.flags |= SC_SEC_ENV_ALG_PRESENT; senv.algorithm = SC_ALGORITHM_GOSTR3410; break; case SC_PKCS15_TYPE_PRKEY_EC: modlen = ((prkey->field_length +7) / 8) * 2; /* 2*nLen */ alg_info = sc_card_find_ec_alg(p15card->card, prkey->field_length); if (alg_info == NULL) { sc_log(ctx, "Card does not support EC with field_size %d", prkey->field_length); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); } senv.algorithm = SC_ALGORITHM_EC; senv.flags |= SC_SEC_ENV_ALG_PRESENT; senv.flags |= SC_SEC_ENV_ALG_REF_PRESENT; senv.algorithm_ref = prkey->field_length; break; /* add other crypto types here */ default: LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key type not supported"); } /* Probably never happens, but better make sure */ if (inlen > sizeof(buf) || outlen < modlen) LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL); memcpy(buf, in, inlen); /* revert data to sign when signing with the GOST key. * TODO: can it be confirmed by the GOST standard? * TODO: tested with RuTokenECP, has to be validated for RuToken. */ if (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410) sc_mem_reverse(buf, inlen); tmp = buf; /* flags: the requested algo * algo_info->flags: what is supported by the card * senv.algorithm_flags: what the card will have to do */ /* if the card has SC_ALGORITHM_NEED_USAGE set, and the key is for signing and decryption, we need to emulate signing */ /* TODO: -DEE assume only RSA keys will ever use _NEED_USAGE */ sc_log(ctx, "supported algorithm flags 0x%X, private key usage 0x%X", alg_info->flags, prkey->usage); if ((alg_info->flags & SC_ALGORITHM_NEED_USAGE) && ((prkey->usage & USAGE_ANY_SIGN) && (prkey->usage & USAGE_ANY_DECIPHER)) ) { size_t tmplen = sizeof(buf); if (flags & SC_ALGORITHM_RSA_RAW) { r = sc_pkcs15_decipher(p15card, obj,flags, in, inlen, out, outlen); LOG_FUNC_RETURN(ctx, r); } if (modlen > tmplen) LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "Buffer too small, needs recompile!"); r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, modlen); /* no padding needed - already done */ flags &= ~SC_ALGORITHM_RSA_PADS; /* instead use raw rsa */ flags |= SC_ALGORITHM_RSA_RAW; LOG_TEST_RET(ctx, r, "Unable to add padding"); r = sc_pkcs15_decipher(p15card, obj,flags, buf, modlen, out, outlen); LOG_FUNC_RETURN(ctx, r); } /* If the card doesn't support the requested algorithm, see if we * can strip the input so a more restrictive algo can be used */ if ((flags == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) && !(alg_info->flags & (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE))) { unsigned int algo; size_t tmplen = sizeof(buf); r = sc_pkcs1_strip_digest_info_prefix(&algo, tmp, inlen, tmp, &tmplen); if (r != SC_SUCCESS || algo == SC_ALGORITHM_RSA_HASH_NONE) { sc_mem_clear(buf, sizeof(buf)); LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); } flags &= ~SC_ALGORITHM_RSA_HASH_NONE; flags |= algo; inlen = tmplen; } r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags); if (r != SC_SUCCESS) { sc_mem_clear(buf, sizeof(buf)); LOG_FUNC_RETURN(ctx, r); } senv.algorithm_flags = sec_flags; sc_log(ctx, "DEE flags:0x%8.8x alg_info->flags:0x%8.8x pad:0x%8.8x sec:0x%8.8x", flags, alg_info->flags, pad_flags, sec_flags); /* add the padding bytes (if necessary) */ if (pad_flags != 0) { size_t tmplen = sizeof(buf); r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, modlen); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to add padding"); inlen = tmplen; } else if ( senv.algorithm == SC_ALGORITHM_RSA && (flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) { /* Add zero-padding if input is shorter than the modulus */ if (inlen < modlen) { if (modlen > sizeof(buf)) return SC_ERROR_BUFFER_TOO_SMALL; memmove(tmp+modlen-inlen, tmp, inlen); memset(tmp, 0, modlen-inlen); } inlen = modlen; } senv.operation = SC_SEC_OPERATION_SIGN; /* optional keyReference attribute (the default value is -1) */ if (prkey->key_reference >= 0) { senv.key_ref_len = 1; senv.key_ref[0] = prkey->key_reference & 0xFF; senv.flags |= SC_SEC_ENV_KEY_REF_PRESENT; } r = sc_lock(p15card->card); LOG_TEST_RET(ctx, r, "sc_lock() failed"); sc_log(ctx, "Private key path '%s'", sc_print_path(&prkey->path)); if (prkey->path.len != 0 || prkey->path.aid.len != 0) { r = select_key_file(p15card, prkey, &senv); if (r < 0) { sc_unlock(p15card->card); LOG_TEST_RET(ctx, r,"Unable to select private key file"); } } r = sc_set_security_env(p15card->card, &senv, 0); if (r < 0) { sc_unlock(p15card->card); LOG_TEST_RET(ctx, r, "sc_set_security_env() failed"); } r = sc_compute_signature(p15card->card, tmp, inlen, out, outlen); if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) if (sc_pkcs15_pincache_revalidate(p15card, obj) == SC_SUCCESS) r = sc_compute_signature(p15card->card, tmp, inlen, out, outlen); sc_mem_clear(buf, sizeof(buf)); sc_unlock(p15card->card); LOG_TEST_RET(ctx, r, "sc_compute_signature() failed"); LOG_FUNC_RETURN(ctx, r); }