/* 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; unsigned int hash_len; switch (algo) { case GNUTLS_PK_EC: /* we do ECDSA */ { ecc_key priv; struct dsa_signature sig; int curve_id = pk_params->flags; if (is_supported_curve(curve_id) == 0) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); _ecc_params_to_privkey(pk_params, &priv); dsa_signature_init (&sig); hash = _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(hash), hash_len); hash_len = vdata->size; } ret = ecc_sign_hash(vdata->data, hash_len, &sig, NULL, rnd_func, &priv, curve_id); if (ret != 0) { gnutls_assert (); ret = GNUTLS_E_PK_SIGN_FAILED; goto ecdsa_fail; } ret = _gnutls_encode_ber_rs (signature, &sig.r, &sig.s); ecdsa_fail: dsa_signature_clear (&sig); _ecc_params_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); hash = _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(hash), 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 (s, signature); 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_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: { int curve = params->flags; ecc_key ecc_priv; ecc_point *R; ecc_point zero; if (params->params_nr != ECC_PRIVATE_PARAMS) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if (is_supported_curve(curve) == 0) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); _ecc_params_to_privkey(params, &ecc_priv); R = ecc_new_point(); /* verify that x,y lie on the curve */ ret = ecc_projective_check_point(&ecc_priv.pubkey, TOMPZ(params->params[ECC_B]), params->params[ECC_PRIME]); if (ret != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto ecc_cleanup; } memcpy(&zero.x, ecc_priv.Gx, sizeof(mpz_t)); memcpy(&zero.y, ecc_priv.Gy, sizeof(mpz_t)); memcpy(&zero.z, ecc_priv.pubkey.z, sizeof(mpz_t)); /* z = 1 */ /* verify that k*(Gx,Gy)=(x,y) */ ret = ecc_mulmod_cached(ecc_priv.k, curve, R, TOMPZ(params->params[ECC_A]), TOMPZ(params->params[ECC_PRIME]), 1); if (ret != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto ecc_cleanup; } if (mpz_cmp(ecc_priv.pubkey.x, R->x) != 0 || mpz_cmp(ecc_priv.pubkey.y, R->y) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto ecc_cleanup; } ret = 0; ecc_cleanup: _ecc_params_clear(&ecc_priv); ecc_del_point(R); } break; default: ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); } return ret; }
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: { ecc_key ecc_pub, ecc_priv; int curve = priv->flags; unsigned long sz; out->data = NULL; if (is_supported_curve(curve) == 0) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); _ecc_params_to_pubkey(pub, &ecc_pub); _ecc_params_to_privkey(priv, &ecc_priv); if (ecc_projective_check_point(&ecc_pub.pubkey, pub->params[ECC_B], pub->params[ECC_PRIME]) != 0) { ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); goto ecc_cleanup; } sz = ECC_BUF_SIZE; out->data = gnutls_malloc(sz); if (out->data == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto ecc_cleanup; } ret = ecc_shared_secret(&ecc_priv, &ecc_pub, out->data, &sz); if (ret != 0) ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ecc_cleanup: _ecc_params_clear(&ecc_pub); _ecc_params_clear(&ecc_priv); if (ret < 0) { gnutls_free(out->data); return ret; } out->size = sz; break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: 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; unsigned int hash_len; switch (algo) { case GNUTLS_PK_EC: /* we do ECDSA */ { ecc_key priv; struct dsa_signature sig; _ecc_params_to_privkey(pk_params, &priv); dsa_signature_init (&sig); hash = _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(hash), hash_len); hash_len = vdata->size; } ret = ecc_sign_hash(vdata->data, hash_len, &sig, NULL, rnd_func, &priv); if (ret != 0) { gnutls_assert (); ret = GNUTLS_E_PK_SIGN_FAILED; goto ecdsa_fail; } ret = _gnutls_encode_ber_rs (signature, &sig.r, &sig.s); ecdsa_fail: dsa_signature_clear (&sig); _ecc_params_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); hash = _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(hash), 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; bigint_t hash, nc, ri; if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } memset(&priv, 0, sizeof(priv)); _rsa_params_to_privkey (pk_params, &priv); nc = rsa_blind (hash, pk_params->params[1] /*e */ , pk_params->params[0] /*m */ , &ri); _gnutls_mpi_release (&hash); if (nc == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto rsa_fail; } rsa_compute_root (&priv, TOMPZ (nc), TOMPZ (nc)); rsa_unblind (nc, ri, pk_params->params[0] /*m */ ); ret = _gnutls_mpi_dprint (nc, signature); rsa_fail: _gnutls_mpi_release (&nc); _gnutls_mpi_release (&ri); 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_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 _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; }
/* This is used for DH or ECDH key derivation. In DH for example * it is given the peers Y and our x, and calculates Y^x */ 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_DH: { bigint_t f, x, prime; bigint_t k = NULL, ff = NULL; unsigned int bits; f = pub->params[DH_Y]; x = priv->params[DH_X]; prime = priv->params[DH_P]; ret = _gnutls_mpi_init_multi(&k, &ff, NULL); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_mpi_modm(ff, f, prime); if (ret < 0) { gnutls_assert(); goto dh_cleanup; } ret = _gnutls_mpi_add_ui(ff, ff, 1); if (ret < 0) { gnutls_assert(); goto dh_cleanup; } /* check if f==0,1,p-1. * or (ff=f+1) equivalently ff==1,2,p */ if ((_gnutls_mpi_cmp_ui(ff, 2) == 0) || (_gnutls_mpi_cmp_ui(ff, 1) == 0) || (_gnutls_mpi_cmp(ff, prime) == 0)) { gnutls_assert(); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto dh_cleanup; } /* prevent denial of service */ bits = _gnutls_mpi_get_nbits(prime); if (bits == 0 || bits > MAX_DH_BITS) { gnutls_assert(); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto dh_cleanup; } ret = _gnutls_mpi_powm(k, f, x, prime); if (ret < 0) { gnutls_assert(); goto dh_cleanup; } ret = _gnutls_mpi_dprint(k, out); if (ret < 0) { gnutls_assert(); goto dh_cleanup; } ret = 0; dh_cleanup: _gnutls_mpi_release(&ff); zrelease_temp_mpi_key(&k); if (ret < 0) goto cleanup; break; } 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_zclear(&ecc_priv); if (ret < 0) goto cleanup; break; } default: gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: return ret; }