/* * Copyright (C) 2010-2012 Free Software Foundation, Inc. * Copyright (C) 2013 Nikos Mavrogiannopoulos * * Author: Nikos Mavrogiannopoulos * * This file is part of GNUTLS. * * The GNUTLS library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * */ /* This file contains the functions needed for RSA/DSA public key * encryption and signatures. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TOMPZ(x) (*((mpz_t*)(x))) static inline const struct ecc_curve *get_supported_curve(int curve); static void rnd_func (void *_ctx, unsigned length, uint8_t * data) { _gnutls_rnd (GNUTLS_RND_RANDOM, data, length); } static void _dsa_params_to_pubkey (const gnutls_pk_params_st * pk_params, struct dsa_public_key *pub) { memcpy (&pub->p, pk_params->params[0], sizeof (mpz_t)); memcpy (&pub->q, pk_params->params[1], sizeof (mpz_t)); memcpy (&pub->g, pk_params->params[2], sizeof (mpz_t)); memcpy (&pub->y, pk_params->params[3], sizeof (mpz_t)); } static void _dsa_params_to_privkey (const gnutls_pk_params_st * pk_params, struct dsa_private_key *pub) { memcpy (&pub->x, pk_params->params[4], sizeof (mpz_t)); } static void _rsa_params_to_privkey (const gnutls_pk_params_st * pk_params, struct rsa_private_key *priv) { memcpy (&priv->d, pk_params->params[2], sizeof (mpz_t)); memcpy (&priv->p, pk_params->params[3], sizeof (mpz_t)); memcpy (&priv->q, pk_params->params[4], sizeof (mpz_t)); memcpy (&priv->c, pk_params->params[5], sizeof (mpz_t)); memcpy (&priv->a, pk_params->params[6], sizeof (mpz_t)); memcpy (&priv->b, pk_params->params[7], sizeof (mpz_t)); priv->size = nettle_mpz_sizeinbase_256_u(TOMPZ(pk_params->params[RSA_MODULUS])); } static void _rsa_params_to_pubkey (const gnutls_pk_params_st * pk_params, struct rsa_public_key *pub) { memcpy (&pub->n, pk_params->params[RSA_MODULUS], sizeof (mpz_t)); memcpy (&pub->e, pk_params->params[RSA_PUB], sizeof (mpz_t)); pub->size = nettle_mpz_sizeinbase_256_u(pub->n); } static int _ecc_params_to_privkey(const gnutls_pk_params_st * pk_params, struct ecc_scalar * priv, const struct ecc_curve *curve) { ecc_scalar_init(priv, curve); if (ecc_scalar_set(priv, pk_params->params[ECC_K]) == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); return 0; } static int _ecc_params_to_pubkey(const gnutls_pk_params_st * pk_params, struct ecc_point * pub, const struct ecc_curve *curve) { ecc_point_init(pub, curve); if (ecc_point_set(pub, pk_params->params[ECC_X], pk_params->params[ECC_Y]) == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); return 0; } static void ecc_shared_secret (struct ecc_scalar * private_key, struct ecc_point * public_key, void *out, unsigned size) { struct ecc_point r; mpz_t x; mpz_init(x); ecc_point_init(&r, public_key->ecc); ecc_point_mul(&r, private_key, public_key); ecc_point_get(&r, x, NULL); nettle_mpz_get_str_256(size, out, x); mpz_clear(x); ecc_point_clear(&r); return; } static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo, gnutls_datum_t * out, const gnutls_pk_params_st * priv, const gnutls_pk_params_st * pub) { int ret; switch (algo) { case GNUTLS_PK_EC: { struct ecc_scalar ecc_priv; struct ecc_point ecc_pub; const struct ecc_curve * curve; out->data = NULL; curve = get_supported_curve(priv->flags); if (curve == NULL) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); ret = _ecc_params_to_pubkey(pub, &ecc_pub, curve); if (ret < 0) return gnutls_assert_val(ret); ret = _ecc_params_to_privkey(priv, &ecc_priv, curve); if (ret < 0) { ecc_point_clear(&ecc_pub); return gnutls_assert_val(ret); } out->size = gnutls_ecc_curve_get_size(priv->flags); /*ecc_size(curve)*sizeof(mp_limb_t);*/ out->data = gnutls_malloc(out->size); if (out->data == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto ecc_cleanup; } ecc_shared_secret(&ecc_priv, &ecc_pub, out->data, out->size); ecc_cleanup: ecc_point_clear(&ecc_pub); ecc_scalar_clear(&ecc_priv); if (ret < 0) goto cleanup; break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: return ret; } static int _wrap_nettle_pk_encrypt (gnutls_pk_algorithm_t algo, gnutls_datum_t * ciphertext, const gnutls_datum_t * plaintext, const gnutls_pk_params_st * pk_params) { int ret; mpz_t p; mpz_init(p); switch (algo) { case GNUTLS_PK_RSA: { struct rsa_public_key pub; _rsa_params_to_pubkey (pk_params, &pub); ret = rsa_encrypt(&pub, NULL, rnd_func, plaintext->size, plaintext->data, p); if (ret == 0) { ret = gnutls_assert_val(GNUTLS_E_ENCRYPTION_FAILED); goto cleanup; } ret = _gnutls_mpi_dprint_size (p, ciphertext, pub.size); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: mpz_clear(p); return ret; } static int _wrap_nettle_pk_decrypt (gnutls_pk_algorithm_t algo, gnutls_datum_t * plaintext, const gnutls_datum_t * ciphertext, const gnutls_pk_params_st * pk_params) { int ret; plaintext->data = NULL; /* make a sexp from pkey */ switch (algo) { case GNUTLS_PK_RSA: { struct rsa_private_key priv; struct rsa_public_key pub; unsigned length; bigint_t c; _rsa_params_to_privkey (pk_params, &priv); _rsa_params_to_pubkey (pk_params, &pub); if (ciphertext->size != pub.size) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (_gnutls_mpi_scan_nz (&c, ciphertext->data, ciphertext->size) != 0) { ret = gnutls_assert_val(GNUTLS_E_MPI_SCAN_FAILED); goto cleanup; } length = pub.size; plaintext->data = gnutls_malloc(length); if (plaintext->data == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto cleanup; } ret = rsa_decrypt_tr(&pub, &priv, NULL, rnd_func, &length, plaintext->data, TOMPZ(c)); _gnutls_mpi_release (&c); plaintext->size = length; if (ret == 0) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto cleanup; } break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: if (ret < 0) gnutls_free(plaintext->data); return ret; } /* in case of DSA puts into data, r,s */ static int _wrap_nettle_pk_sign (gnutls_pk_algorithm_t algo, gnutls_datum_t * signature, const gnutls_datum_t * vdata, const gnutls_pk_params_st * pk_params) { int ret; unsigned int hash_len; const mac_entry_st* me; switch (algo) { case GNUTLS_PK_EC: /* we do ECDSA */ { struct ecc_scalar priv; struct dsa_signature sig; int curve_id = pk_params->flags; const struct ecc_curve * curve; curve = get_supported_curve(curve_id); if (curve == NULL) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); ret = _ecc_params_to_privkey(pk_params, &priv, curve); if (ret < 0) return gnutls_assert_val(ret); dsa_signature_init (&sig); me = _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) { gnutls_assert (); _gnutls_debug_log("Security level of algorithm requires hash %s(%d) or better\n", _gnutls_mac_get_name(me), hash_len); hash_len = vdata->size; } ecdsa_sign(&priv, NULL, rnd_func, hash_len, vdata->data, &sig); ret = _gnutls_encode_ber_rs (signature, &sig.r, &sig.s); dsa_signature_clear (&sig); ecc_scalar_clear( &priv); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } case GNUTLS_PK_DSA: { struct dsa_public_key pub; struct dsa_private_key priv; struct dsa_signature sig; memset(&priv, 0, sizeof(priv)); memset(&pub, 0, sizeof(pub)); _dsa_params_to_pubkey (pk_params, &pub); _dsa_params_to_privkey (pk_params, &priv); dsa_signature_init (&sig); me = _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) { gnutls_assert (); _gnutls_debug_log("Security level of algorithm requires hash %s(%d) or better\n", _gnutls_mac_get_name(me), hash_len); hash_len = vdata->size; } ret = _dsa_sign (&pub, &priv, NULL, rnd_func, hash_len, vdata->data, &sig); if (ret == 0) { gnutls_assert (); ret = GNUTLS_E_PK_SIGN_FAILED; goto dsa_fail; } ret = _gnutls_encode_ber_rs (signature, &sig.r, &sig.s); dsa_fail: dsa_signature_clear (&sig); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } case GNUTLS_PK_RSA: { struct rsa_private_key priv; struct rsa_public_key pub; mpz_t s; _rsa_params_to_privkey (pk_params, &priv); _rsa_params_to_pubkey (pk_params, &pub); mpz_init(s); ret = rsa_pkcs1_sign_tr(&pub, &priv, NULL, rnd_func, vdata->size, vdata->data, s); if (ret == 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIGN_FAILED; goto rsa_fail; } ret = _gnutls_mpi_dprint_size (s, signature, pub.size); rsa_fail: mpz_clear(s); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: return ret; } static int _wrap_nettle_pk_verify (gnutls_pk_algorithm_t algo, const gnutls_datum_t * vdata, const gnutls_datum_t * signature, const gnutls_pk_params_st * pk_params) { int ret; unsigned int hash_len; bigint_t tmp[2] = { NULL, NULL }; switch (algo) { case GNUTLS_PK_EC: /* ECDSA */ { struct ecc_point pub; struct dsa_signature sig; int curve_id = pk_params->flags; const struct ecc_curve * curve; curve = get_supported_curve(curve_id); if (curve == NULL) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]); if (ret < 0) return gnutls_assert_val(ret); ret = _ecc_params_to_pubkey(pk_params, &pub, curve); if (ret < 0) { gnutls_assert(); goto cleanup; } memcpy (&sig.r, tmp[0], sizeof (sig.r)); memcpy (&sig.s, tmp[1], sizeof (sig.s)); _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) hash_len = vdata->size; ret = ecdsa_verify(&pub, hash_len, vdata->data, &sig); if (ret == 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; } else ret = 0; ecc_point_clear( &pub); break; } case GNUTLS_PK_DSA: { struct dsa_public_key pub; struct dsa_signature sig; ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]); if (ret < 0) { gnutls_assert (); goto cleanup; } memset(&pub, 0, sizeof(pub)); _dsa_params_to_pubkey (pk_params, &pub); memcpy (&sig.r, tmp[0], sizeof (sig.r)); memcpy (&sig.s, tmp[1], sizeof (sig.s)); _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) hash_len = vdata->size; ret = _dsa_verify (&pub, hash_len, vdata->data, &sig); if (ret == 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; } else ret = 0; break; } case GNUTLS_PK_RSA: { struct rsa_public_key pub; _rsa_params_to_pubkey (pk_params, &pub); if (signature->size != pub.size) return gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED); ret = _gnutls_mpi_scan_nz (&tmp[0], signature->data, signature->size); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = rsa_pkcs1_verify (&pub, vdata->size, vdata->data, TOMPZ(tmp[0])); if (ret == 0) ret = gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED); else ret = 0; break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } cleanup: _gnutls_mpi_release (&tmp[0]); _gnutls_mpi_release (&tmp[1]); return ret; } static inline const struct ecc_curve *get_supported_curve(int curve) { switch(curve) { case GNUTLS_ECC_CURVE_SECP192R1: return &nettle_secp_192r1; case GNUTLS_ECC_CURVE_SECP224R1: return &nettle_secp_224r1; case GNUTLS_ECC_CURVE_SECP256R1: return &nettle_secp_256r1; case GNUTLS_ECC_CURVE_SECP384R1: return &nettle_secp_384r1; case GNUTLS_ECC_CURVE_SECP521R1: return &nettle_secp_521r1; default: return NULL; } } static int wrap_nettle_pk_generate_params (gnutls_pk_algorithm_t algo, unsigned int level /*bits */ , gnutls_pk_params_st * params) { int ret; unsigned int i, q_bits; memset(params, 0, sizeof(*params)); switch (algo) { case GNUTLS_PK_DSA: { struct dsa_public_key pub; struct dsa_private_key priv; dsa_public_key_init (&pub); dsa_private_key_init (&priv); /* the best would be to use _gnutls_pk_bits_to_subgroup_bits() * but we do NIST DSA here */ if (level <= 1024) q_bits = 160; else q_bits = 256; ret = dsa_generate_keypair (&pub, &priv, NULL, rnd_func, NULL, NULL, level, q_bits); if (ret != 1) { gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto dsa_fail; } params->params_nr = 0; for (i = 0; i < DSA_PRIVATE_PARAMS; i++) { params->params[i] = _gnutls_mpi_alloc_like (&pub.p); if (params->params[i] == NULL) { ret = GNUTLS_E_MEMORY_ERROR; goto dsa_fail; } params->params_nr++; } ret = 0; _gnutls_mpi_set (params->params[0], pub.p); _gnutls_mpi_set (params->params[1], pub.q); _gnutls_mpi_set (params->params[2], pub.g); _gnutls_mpi_set (params->params[3], pub.y); _gnutls_mpi_set (params->params[4], priv.x); dsa_fail: dsa_private_key_clear (&priv); dsa_public_key_clear (&pub); if (ret < 0) goto fail; break; } case GNUTLS_PK_RSA: { struct rsa_public_key pub; struct rsa_private_key priv; rsa_public_key_init (&pub); rsa_private_key_init (&priv); _gnutls_mpi_set_ui (&pub.e, 65537); ret = rsa_generate_keypair (&pub, &priv, NULL, rnd_func, NULL, NULL, level, 0); if (ret != 1) { gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto rsa_fail; } params->params_nr = 0; for (i = 0; i < RSA_PRIVATE_PARAMS; i++) { params->params[i] = _gnutls_mpi_alloc_like (&pub.n); if (params->params[i] == NULL) { ret = GNUTLS_E_MEMORY_ERROR; goto rsa_fail; } params->params_nr++; } ret = 0; _gnutls_mpi_set (params->params[0], pub.n); _gnutls_mpi_set (params->params[1], pub.e); _gnutls_mpi_set (params->params[2], priv.d); _gnutls_mpi_set (params->params[3], priv.p); _gnutls_mpi_set (params->params[4], priv.q); _gnutls_mpi_set (params->params[5], priv.c); _gnutls_mpi_set (params->params[6], priv.a); _gnutls_mpi_set (params->params[7], priv.b); rsa_fail: rsa_private_key_clear (&priv); rsa_public_key_clear (&pub); if (ret < 0) goto fail; break; } case GNUTLS_PK_EC: { struct ecc_scalar key; struct ecc_point pub; const struct ecc_curve* curve; curve = get_supported_curve(level); if (curve == NULL) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); ecc_scalar_init(&key, curve); ecc_point_init(&pub, curve); ecdsa_generate_keypair(&pub, &key, NULL, rnd_func); params->params[ECC_X] = _gnutls_mpi_new (0); params->params[ECC_Y] = _gnutls_mpi_new (0); params->params[ECC_K] = _gnutls_mpi_new (0); if (params->params[ECC_X] == NULL || params->params[ECC_Y] == NULL || params->params[ECC_K] == NULL) { _gnutls_mpi_release(¶ms->params[ECC_X]); _gnutls_mpi_release(¶ms->params[ECC_Y]); _gnutls_mpi_release(¶ms->params[ECC_K]); goto ecc_cleanup; } params->flags = level; params->params_nr = ECC_PRIVATE_PARAMS; ecc_point_get(&pub, TOMPZ(params->params[ECC_X]), TOMPZ(params->params[ECC_Y])); ecc_scalar_get(&key, TOMPZ(params->params[ECC_K])); ecc_cleanup: ecc_point_clear(&pub); ecc_scalar_clear(&key); break; } default: gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } return 0; fail: for (i = 0; i < params->params_nr; i++) { _gnutls_mpi_release (¶ms->params[i]); } params->params_nr = 0; return ret; } static int wrap_nettle_pk_verify_params (gnutls_pk_algorithm_t algo, const gnutls_pk_params_st * params) { int ret; switch (algo) { case GNUTLS_PK_RSA: { bigint_t t1 = NULL, t2 = NULL; if (params->params_nr != RSA_PRIVATE_PARAMS) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); t1 = _gnutls_mpi_new (256); if (t1 == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _gnutls_mpi_mulm (t1, params->params[RSA_PRIME1], params->params[RSA_PRIME2], params->params[RSA_MODULUS]); if (_gnutls_mpi_cmp_ui(t1, 0) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } mpz_invert (TOMPZ(t1), TOMPZ (params->params[RSA_PRIME2]), TOMPZ (params->params[RSA_PRIME1])); if (_gnutls_mpi_cmp(t1, params->params[RSA_COEF]) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } /* [RSA_PRIME1] = d % p-1, [RSA_PRIME2] = d % q-1 */ _gnutls_mpi_sub_ui (t1, params->params[RSA_PRIME1], 1); t2 = _gnutls_mpi_mod (params->params[RSA_PRIV], t1); if (t2 == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto rsa_cleanup; } if (_gnutls_mpi_cmp(params->params[RSA_E1], t2) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } _gnutls_mpi_sub_ui (t1, params->params[RSA_PRIME2], 1); _gnutls_mpi_release(&t2); t2 = _gnutls_mpi_mod (params->params[RSA_PRIV], t1); if (t2 == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto rsa_cleanup; } if (_gnutls_mpi_cmp(params->params[RSA_E2], t2) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } ret = 0; rsa_cleanup: _gnutls_mpi_release(&t1); _gnutls_mpi_release(&t2); } break; case GNUTLS_PK_DSA: { bigint_t t1 = NULL; if (params->params_nr != DSA_PRIVATE_PARAMS) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); t1 = _gnutls_mpi_new (256); if (t1 == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _gnutls_mpi_powm (t1, params->params[DSA_G], params->params[DSA_X], params->params[DSA_P]); if (_gnutls_mpi_cmp(t1, params->params[DSA_Y]) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto dsa_cleanup; } ret = 0; dsa_cleanup: _gnutls_mpi_release(&t1); } break; case GNUTLS_PK_EC: { struct ecc_point r, pub; struct ecc_scalar priv; mpz_t x1, y1, x2, y2; const struct ecc_curve * curve; if (params->params_nr != ECC_PRIVATE_PARAMS) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); curve = get_supported_curve(params->flags); if (curve == NULL) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); ret = _ecc_params_to_pubkey(params, &pub, curve); if (ret < 0) return gnutls_assert_val(ret); ret = _ecc_params_to_privkey(params, &priv, curve); if (ret < 0) { ecc_point_clear(&pub); return gnutls_assert_val(ret); } ecc_point_init(&r, curve); /* verify that x,y lie on the curve */ ret = ecc_point_set(&r, TOMPZ(params->params[ECC_X]), TOMPZ(params->params[ECC_Y])); if (ret == 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto ecc_cleanup; } ecc_point_clear(&r); ecc_point_init(&r, curve); ecc_point_mul_g(&r, &priv); mpz_init(x1); mpz_init(y1); ecc_point_get(&r, x1, y1); ecc_point_clear(&r); mpz_init(x2); mpz_init(y2); ecc_point_get(&pub, x2, y2); /* verify that k*(Gx,Gy)=(x,y) */ if (mpz_cmp(x1, x2) != 0 || mpz_cmp(y1, y2) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto ecc_cleanup; } ret = 0; ecc_cleanup: ecc_scalar_clear(&priv); ecc_point_clear(&pub); } break; default: ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); } return ret; } static int calc_rsa_exp (gnutls_pk_params_st* params) { bigint_t tmp = _gnutls_mpi_alloc_like (params->params[0]); if (params->params_nr < RSA_PRIVATE_PARAMS - 2) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } if (tmp == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* [6] = d % p-1, [7] = d % q-1 */ _gnutls_mpi_sub_ui (tmp, params->params[3], 1); params->params[6] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp); _gnutls_mpi_sub_ui (tmp, params->params[4], 1); params->params[7] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp); _gnutls_mpi_release (&tmp); if (params->params[7] == NULL || params->params[6] == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } return 0; } static int wrap_nettle_pk_fixup (gnutls_pk_algorithm_t algo, gnutls_direction_t direction, gnutls_pk_params_st * params) { int result; if (direction == GNUTLS_IMPORT && algo == GNUTLS_PK_RSA) { /* do not trust the generated values. Some old private keys * generated by us have mess on the values. Those were very * old but it seemed some of the shipped example private * keys were as old. */ mpz_invert (TOMPZ (params->params[RSA_COEF]), TOMPZ (params->params[RSA_PRIME2]), TOMPZ (params->params[RSA_PRIME1])); /* calculate exp1 [6] and exp2 [7] */ _gnutls_mpi_release (¶ms->params[RSA_E1]); _gnutls_mpi_release (¶ms->params[RSA_E2]); result = calc_rsa_exp (params); if (result < 0) { gnutls_assert (); return result; } params->params_nr = RSA_PRIVATE_PARAMS; } return 0; } static int extract_digest_info(const struct rsa_public_key *key, gnutls_datum_t *di, uint8_t** rdi, const mpz_t signature) { unsigned i; int ret; mpz_t m; uint8_t *em; if (key->size == 0) return 0; em = gnutls_malloc(key->size); if (em == NULL) return 0; mpz_init (m); mpz_powm(m, signature, key->e, key->n); nettle_mpz_get_str_256(key->size, em, m); mpz_clear(m); if (em[0] != 0 || em[1] != 1) { ret = 0; goto cleanup; } for (i = 2; i < key->size; i++) { if (em[i] == 0 && i > 2) break; if (em[i] != 0xff) { ret = 0; goto cleanup; } } i++; *rdi = em; di->data = &em[i]; di->size = key->size - i; return 1; cleanup: gnutls_free(em); return ret; } /* Given a signature and parameters, it should return * the hash algorithm used in the signature. This is a kludge * but until we deprecate gnutls_pubkey_get_verify_algorithm() * we depend on it. */ static int wrap_nettle_hash_algorithm (gnutls_pk_algorithm_t pk, const gnutls_datum_t * sig, gnutls_pk_params_st * issuer_params, gnutls_digest_algorithm_t* hash_algo) { uint8_t digest[MAX_HASH_SIZE]; uint8_t* rdi = NULL; gnutls_datum_t di; unsigned digest_size; mpz_t s; struct rsa_public_key pub; const mac_entry_st* me; int ret; mpz_init(s); switch (pk) { case GNUTLS_PK_DSA: case GNUTLS_PK_EC: me = _gnutls_dsa_q_to_hash (pk, issuer_params, NULL); if (hash_algo) *hash_algo = me->id; ret = 0; break; case GNUTLS_PK_RSA: if (sig == NULL) { /* return a sensible algorithm */ if (hash_algo) *hash_algo = GNUTLS_DIG_SHA256; return 0; } _rsa_params_to_pubkey (issuer_params, &pub); digest_size = sizeof(digest); nettle_mpz_set_str_256_u(s, sig->size, sig->data); ret = extract_digest_info( &pub, &di, &rdi, s); if (ret == 0) { ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; gnutls_assert (); goto cleanup; } digest_size = sizeof(digest); if ((ret = decode_ber_digest_info (&di, hash_algo, digest, &digest_size)) < 0) { gnutls_assert (); goto cleanup; } if (digest_size != _gnutls_hash_get_algo_len (mac_to_entry(*hash_algo))) { gnutls_assert (); ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; goto cleanup; } ret = 0; break; default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; } cleanup: mpz_clear(s); gnutls_free(rdi); return ret; } int crypto_pk_prio = INT_MAX; gnutls_crypto_pk_st _gnutls_pk_ops = { .hash_algorithm = wrap_nettle_hash_algorithm, .encrypt = _wrap_nettle_pk_encrypt, .decrypt = _wrap_nettle_pk_decrypt, .sign = _wrap_nettle_pk_sign, .verify = _wrap_nettle_pk_verify, .verify_params = wrap_nettle_pk_verify_params, .generate = wrap_nettle_pk_generate_params, .pk_fixup_private_params = wrap_nettle_pk_fixup, .derive = _wrap_nettle_pk_derive, };