/** * gnutls_dh_params_export_raw - export the raw DH parameters * @params: Holds the DH parameters * @prime: will hold the new prime * @generator: will hold the new generator * @bits: if non null will hold is the prime's number of bits * * This function will export the pair of prime and generator for use * in the Diffie-Hellman key exchange. The new parameters will be * allocated using gnutls_malloc() and will be stored in the * appropriate datum. * * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned, * otherwise an error code is returned. **/ int gnutls_dh_params_export_raw (gnutls_dh_params_t params, gnutls_datum_t * prime, gnutls_datum_t * generator, unsigned int *bits) { int ret; if (params->params[1] == NULL || params->params[0] == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } ret = _gnutls_mpi_dprint (params->params[1], generator); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_mpi_dprint (params->params[0], prime); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (generator); return ret; } if (bits) *bits = _gnutls_mpi_get_nbits (params->params[0]); return 0; }
/* This function gets the signature parameters and encodes * them into a way for _gnutls_pk_verify to use. */ static cdk_error_t sig_to_datum (gnutls_datum_t * r_sig, cdk_pkt_signature_t sig) { int err; cdk_error_t rc; if (!r_sig || !sig) return CDK_Inv_Value; rc = 0; if (is_RSA (sig->pubkey_algo)) { err = _gnutls_mpi_dprint (sig->mpi[0], r_sig); if (err < 0) rc = map_gnutls_error (err); } else if (is_DSA (sig->pubkey_algo)) { err = _gnutls_encode_ber_rs (r_sig, sig->mpi[0], sig->mpi[1]); if (err < 0) rc = map_gnutls_error (err); } else rc = CDK_Inv_Algo; return rc; }
int _gnutls_buffer_append_mpi (gnutls_buffer_st * buf, int pfx_size, bigint_t mpi, int lz) { gnutls_datum_t dd; int ret; if (lz) ret = _gnutls_mpi_dprint_lz (mpi, &dd); else ret = _gnutls_mpi_dprint (mpi, &dd); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_data_prefix(buf, pfx_size, dd.data, dd.size); _gnutls_free_datum(&dd); return ret; }
/** * gnutls_pkcs11_copy_x509_privkey2: * @token_url: A PKCS #11 URL specifying a token * @key: A private key * @label: A name to be used for the stored data * @cid: The CKA_ID to set for the object -if NULL, the ID will be derived from the public key * @key_usage: One of GNUTLS_KEY_* * @flags: One of GNUTLS_PKCS11_OBJ_* flags * * This function will copy a private key into a PKCS #11 token specified by * a URL. It is highly recommended flags to contain %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE * unless there is a strong reason not to. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 **/ int gnutls_pkcs11_copy_x509_privkey2(const char *token_url, gnutls_x509_privkey_t key, const char *label, const gnutls_datum_t *cid, unsigned int key_usage, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; size_t id_size; uint8_t id[20]; struct ck_attribute a[32]; ck_object_class_t class = CKO_PRIVATE_KEY; ck_object_handle_t ctx; ck_key_type_t type; int a_val; gnutls_pk_algorithm_t pk; gnutls_datum_t p, q, g, y, x; gnutls_datum_t m, e, d, u, exp1, exp2; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; memset(&p, 0, sizeof(p)); memset(&q, 0, sizeof(q)); memset(&g, 0, sizeof(g)); memset(&y, 0, sizeof(y)); memset(&x, 0, sizeof(x)); memset(&m, 0, sizeof(m)); memset(&e, 0, sizeof(e)); memset(&d, 0, sizeof(d)); memset(&u, 0, sizeof(u)); memset(&exp1, 0, sizeof(exp1)); memset(&exp2, 0, sizeof(exp2)); ret = pkcs11_url_to_info(token_url, &info, 0); if (ret < 0) { gnutls_assert(); return ret; } ret = pkcs11_open_session(&sinfo, NULL, info, SESSION_WRITE | pkcs11_obj_flags_to_int(flags)); p11_kit_uri_free(info); if (ret < 0) { gnutls_assert(); return ret; } pk = gnutls_x509_privkey_get_pk_algorithm(key); FIX_KEY_USAGE(pk, key_usage); /* FIXME: copy key usage flags */ a_val = 0; a[a_val].type = CKA_CLASS; a[a_val].value = &class; a[a_val].value_len = sizeof(class); a_val++; a[a_val].type = CKA_ID; if (cid == NULL || cid->size == 0) { id_size = sizeof(id); ret = gnutls_x509_privkey_get_key_id(key, 0, id, &id_size); if (ret < 0) { p11_kit_uri_free(info); gnutls_assert(); return ret; } a[a_val].value = id; a[a_val].value_len = id_size; } else { a[a_val].value = cid->data; a[a_val].value_len = cid->size; } a_val++; a[a_val].type = CKA_SIGN; if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) { a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); } else { a[a_val].value = (void*)&fval; a[a_val].value_len = sizeof(fval); } a_val++; if (pk == GNUTLS_PK_RSA) { a[a_val].type = CKA_DECRYPT; if (key_usage & (GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_DECIPHER_ONLY)) { a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); } else { a[a_val].value = (void*)&fval; a[a_val].value_len = sizeof(fval); } a_val++; } a[a_val].type = CKA_TOKEN; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; /* a private key is set always as private unless * requested otherwise */ if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } else { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH) { a[a_val].type = CKA_ALWAYS_AUTHENTICATE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_EXTRACTABLE) { a[a_val].type = CKA_EXTRACTABLE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); (a_val)++; } else { a[a_val].type = CKA_EXTRACTABLE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); (a_val)++; } if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) { a[a_val].type = CKA_SENSITIVE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } else { a[a_val].type = CKA_SENSITIVE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } switch (pk) { case GNUTLS_PK_RSA: { ret = gnutls_x509_privkey_export_rsa_raw2(key, &m, &e, &d, &p, &q, &u, &exp1, &exp2); if (ret < 0) { gnutls_assert(); goto cleanup; } type = CKK_RSA; skip_leading_zeros(&m); skip_leading_zeros(&e); skip_leading_zeros(&d); skip_leading_zeros(&p); skip_leading_zeros(&q); skip_leading_zeros(&u); skip_leading_zeros(&exp1); skip_leading_zeros(&exp2); a[a_val].type = CKA_MODULUS; a[a_val].value = m.data; a[a_val].value_len = m.size; a_val++; a[a_val].type = CKA_PUBLIC_EXPONENT; a[a_val].value = e.data; a[a_val].value_len = e.size; a_val++; a[a_val].type = CKA_PRIVATE_EXPONENT; a[a_val].value = d.data; a[a_val].value_len = d.size; a_val++; a[a_val].type = CKA_PRIME_1; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_PRIME_2; a[a_val].value = q.data; a[a_val].value_len = q.size; a_val++; a[a_val].type = CKA_COEFFICIENT; a[a_val].value = u.data; a[a_val].value_len = u.size; a_val++; a[a_val].type = CKA_EXPONENT_1; a[a_val].value = exp1.data; a[a_val].value_len = exp1.size; a_val++; a[a_val].type = CKA_EXPONENT_2; a[a_val].value = exp2.data; a[a_val].value_len = exp2.size; a_val++; break; } case GNUTLS_PK_DSA: { ret = gnutls_x509_privkey_export_dsa_raw(key, &p, &q, &g, &y, &x); if (ret < 0) { gnutls_assert(); goto cleanup; } type = CKK_DSA; skip_leading_zeros(&p); skip_leading_zeros(&q); skip_leading_zeros(&g); skip_leading_zeros(&y); skip_leading_zeros(&x); a[a_val].type = CKA_PRIME; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_SUBPRIME; a[a_val].value = q.data; a[a_val].value_len = q.size; a_val++; a[a_val].type = CKA_BASE; a[a_val].value = g.data; a[a_val].value_len = g.size; a_val++; a[a_val].type = CKA_VALUE; a[a_val].value = x.data; a[a_val].value_len = x.size; a_val++; break; } case GNUTLS_PK_EC: { ret = _gnutls_x509_write_ecc_params(key->params.flags, &p); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_mpi_dprint(key->params. params[ECC_K], &x); if (ret < 0) { gnutls_assert(); goto cleanup; } type = CKK_ECDSA; a[a_val].type = CKA_EC_PARAMS; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_VALUE; a[a_val].value = x.data; a[a_val].value_len = x.size; a_val++; break; } default: gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; goto cleanup; } a[a_val].type = CKA_KEY_TYPE; a[a_val].value = &type; a[a_val].value_len = sizeof(type); a_val++; rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &ctx); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } ret = 0; cleanup: switch (pk) { case GNUTLS_PK_RSA: { gnutls_free(m.data); gnutls_free(e.data); gnutls_free(d.data); gnutls_free(p.data); gnutls_free(q.data); gnutls_free(u.data); gnutls_free(exp1.data); gnutls_free(exp2.data); break; } case GNUTLS_PK_DSA: { gnutls_free(p.data); gnutls_free(q.data); gnutls_free(g.data); gnutls_free(y.data); gnutls_free(x.data); break; } case GNUTLS_PK_EC: { gnutls_free(p.data); gnutls_free(x.data); break; } default: gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; break; } if (sinfo.pks != 0) pkcs11_close_session(&sinfo); return ret; }
static int _get_sk_dsa_raw(gnutls_openpgp_privkey_t pkey, gnutls_openpgp_keyid_t keyid, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * g, gnutls_datum_t * y, gnutls_datum_t * x) { int pk_algorithm, ret; cdk_packet_t pkt; uint32_t kid32[2]; gnutls_pk_params_st params; if (pkey == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } KEYID_IMPORT(kid32, keyid); pkt = _gnutls_openpgp_find_key(pkey->knode, kid32, 1); if (pkt == NULL) { gnutls_assert(); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } pk_algorithm = _gnutls_openpgp_get_algo(pkt->pkt.secret_key->pk->pubkey_algo); if (pk_algorithm != GNUTLS_PK_DSA) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } ret = _gnutls_openpgp_privkey_get_mpis(pkey, kid32, ¶ms); if (ret < 0) { gnutls_assert(); return ret; } /* P */ ret = _gnutls_mpi_dprint(params.params[0], p); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Q */ ret = _gnutls_mpi_dprint(params.params[1], q); if (ret < 0) { gnutls_assert(); _gnutls_free_datum(p); goto cleanup; } /* G */ ret = _gnutls_mpi_dprint(params.params[2], g); if (ret < 0) { gnutls_assert(); _gnutls_free_datum(p); _gnutls_free_datum(q); goto cleanup; } /* Y */ ret = _gnutls_mpi_dprint(params.params[3], y); if (ret < 0) { gnutls_assert(); _gnutls_free_datum(p); _gnutls_free_datum(g); _gnutls_free_datum(q); goto cleanup; } ret = _gnutls_mpi_dprint(params.params[4], x); if (ret < 0) { gnutls_assert(); _gnutls_free_datum(y); _gnutls_free_datum(p); _gnutls_free_datum(g); _gnutls_free_datum(q); goto cleanup; } ret = 0; cleanup: gnutls_pk_params_clear(¶ms); gnutls_pk_params_release(¶ms); return ret; }
int _gnutls_proc_dh_common_client_kx (gnutls_session_t session, uint8_t * data, size_t _data_size, bigint_t g, bigint_t p, gnutls_datum_t* psk_key) { uint16_t n_Y; size_t _n_Y; int ret; ssize_t data_size = _data_size; DECR_LEN (data_size, 2); n_Y = _gnutls_read_uint16 (&data[0]); _n_Y = n_Y; DECR_LEN (data_size, n_Y); if (_gnutls_mpi_scan_nz (&session->key.client_Y, &data[2], _n_Y)) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } _gnutls_dh_set_peer_public (session, session->key.client_Y); ret = gnutls_calc_dh_key (&session->key.KEY, session->key.client_Y, session->key.dh_secret, p); if (ret < 0) return gnutls_assert_val(ret); _gnutls_mpi_release (&session->key.client_Y); _gnutls_mpi_release (&session->key.dh_secret); if (psk_key == NULL) { ret = _gnutls_mpi_dprint (session->key.KEY, &session->key.key); } else /* In DHE_PSK the key is set differently */ { gnutls_datum_t tmp_dh_key; ret = _gnutls_mpi_dprint (session->key.KEY, &tmp_dh_key); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_set_psk_session_key (session, psk_key, &tmp_dh_key); _gnutls_free_datum (&tmp_dh_key); } _gnutls_mpi_release (&session->key.KEY); if (ret < 0) { return ret; } return 0; }
int _gnutls_gen_dh_common_client_kx_int (gnutls_session_t session, gnutls_buffer_st* data, gnutls_datum_t* pskkey) { bigint_t x = NULL, X = NULL; int ret; ret = gnutls_calc_dh_secret (&X, &x, session->key.client_g, session->key.client_p, 0); if (ret < 0) { gnutls_assert (); goto error; } _gnutls_dh_set_secret_bits (session, _gnutls_mpi_get_nbits (x)); ret = _gnutls_buffer_append_mpi( data, 16, X, 0); if (ret < 0) { gnutls_assert(); goto error; } /* calculate the key after calculating the message */ ret = gnutls_calc_dh_key (&session->key.KEY, session->key.client_Y, x, session->key.client_p); if (ret < 0) { gnutls_assert(); goto error; } /* THESE SHOULD BE DISCARDED */ _gnutls_mpi_release (&session->key.client_Y); _gnutls_mpi_release (&session->key.client_p); _gnutls_mpi_release (&session->key.client_g); if (_gnutls_cipher_suite_get_kx_algo (session->security_parameters.cipher_suite) != GNUTLS_KX_DHE_PSK) { ret = _gnutls_mpi_dprint (session->key.KEY, &session->key.key); } else /* In DHE_PSK the key is set differently */ { gnutls_datum_t tmp_dh_key; ret = _gnutls_mpi_dprint (session->key.KEY, &tmp_dh_key); if (ret < 0) { gnutls_assert (); goto error; } ret = _gnutls_set_psk_session_key (session, pskkey, &tmp_dh_key); _gnutls_free_datum (&tmp_dh_key); } _gnutls_mpi_release (&session->key.KEY); if (ret < 0) { gnutls_assert (); goto error; } ret = data->length; error: _gnutls_mpi_release (&x); _gnutls_mpi_release (&X); return ret; }
int _gnutls_gen_dh_common_client_kx (gnutls_session_t session, opaque ** data) { mpi_t x = NULL, X = NULL; size_t n_X; int ret; *data = NULL; X = gnutls_calc_dh_secret (&x, session->key->client_g, session->key->client_p); if (X == NULL || x == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto error; } _gnutls_dh_set_secret_bits (session, _gnutls_mpi_get_nbits (x)); _gnutls_mpi_print (NULL, &n_X, X); (*data) = gnutls_malloc (n_X + 2); if (*data == NULL) { ret = GNUTLS_E_MEMORY_ERROR; goto error; } _gnutls_mpi_print (&(*data)[2], &n_X, X); _gnutls_mpi_release (&X); _gnutls_write_uint16 (n_X, &(*data)[0]); /* calculate the key after calculating the message */ session->key->KEY = gnutls_calc_dh_key (session->key->client_Y, x, session->key->client_p); _gnutls_mpi_release (&x); if (session->key->KEY == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto error; } _gnutls_dh_set_peer_public (session, session->key->client_Y); /* THESE SHOULD BE DISCARDED */ _gnutls_mpi_release (&session->key->client_Y); _gnutls_mpi_release (&session->key->client_p); _gnutls_mpi_release (&session->key->client_g); if (_gnutls_cipher_suite_get_kx_algo (&session->security_parameters.current_cipher_suite) != GNUTLS_KX_DHE_PSK) { ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY); } else /* In DHE_PSK the key is set differently */ { gnutls_datum tmp_dh_key; ret = _gnutls_mpi_dprint (&tmp_dh_key, session->key->KEY); if (ret < 0) { gnutls_assert (); goto error; } ret = _gnutls_set_psk_session_key (session, &tmp_dh_key); _gnutls_free_datum (&tmp_dh_key); } _gnutls_mpi_release (&session->key->KEY); if (ret < 0) { gnutls_assert (); goto error; } return n_X + 2; error: _gnutls_mpi_release (&x); _gnutls_mpi_release (&X); gnutls_free (*data); *data = NULL; return ret; }
/** * gnutls_x509_privkey_export_rsa_raw - This function will export the RSA private key * @key: a structure that holds the rsa parameters * @m: will hold the modulus * @e: will hold the public exponent * @d: will hold the private exponent * @p: will hold the first prime (p) * @q: will hold the second prime (q) * @u: will hold the coefficient * * This function will export the RSA private key's parameters found in the given * structure. The new parameters will be allocated using * gnutls_malloc() and will be stored in the appropriate datum. * **/ int gnutls_x509_privkey_export_rsa_raw (gnutls_x509_privkey_t key, gnutls_datum_t * m, gnutls_datum_t * e, gnutls_datum_t * d, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * u) { int ret; mpi_t coeff = NULL; if (key == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } m->data = e->data = d->data = p->data = q->data = u->data = NULL; m->size = e->size = d->size = p->size = q->size = u->size = 0; ret = _gnutls_mpi_dprint (m, key->params[0]); if (ret < 0) { gnutls_assert (); goto error; } /* E */ ret = _gnutls_mpi_dprint (e, key->params[1]); if (ret < 0) { gnutls_assert (); goto error; } /* D */ ret = _gnutls_mpi_dprint (d, key->params[2]); if (ret < 0) { gnutls_assert (); goto error; } /* P */ ret = _gnutls_mpi_dprint (p, key->params[3]); if (ret < 0) { gnutls_assert (); goto error; } /* Q */ ret = _gnutls_mpi_dprint (q, key->params[4]); if (ret < 0) { gnutls_assert (); goto error; } #ifdef CALC_COEFF coeff = _gnutls_mpi_snew (_gnutls_mpi_get_nbits (key->params[0])); if (coeff == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto error; } _gnutls_mpi_invm (coeff, key->params[4], key->params[3]); ret = _gnutls_mpi_dprint (u, coeff); if (ret < 0) { gnutls_assert (); goto error; } _gnutls_mpi_release (&coeff); #else /* U */ ret = _gnutls_mpi_dprint (u, key->params[5]); if (ret < 0) { gnutls_assert (); goto error; } #endif return 0; error: _gnutls_free_datum (m); _gnutls_free_datum (d); _gnutls_free_datum (e); _gnutls_free_datum (p); _gnutls_free_datum (q); _gnutls_mpi_release (&coeff); return ret; }
/* in case of DSA puts into data, r,s */ static int _wrap_gcry_pk_sign (gnutls_pk_algorithm_t algo, gnutls_datum_t * signature, const gnutls_datum_t * vdata, const gnutls_pk_params_st * pk_params) { gcry_sexp_t s_hash = NULL, s_key = NULL, s_sig = NULL; gcry_sexp_t list = NULL; int rc = -1, ret; bigint_t hash; bigint_t res[2] = { NULL, NULL }; if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } /* make a sexp from pkey */ switch (algo) { case GNUTLS_PK_DSA: if (pk_params->params_nr >= 5) rc = gcry_sexp_build (&s_key, NULL, "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))", pk_params->params[0], pk_params->params[1], pk_params->params[2], pk_params->params[3], pk_params->params[4]); else { gnutls_assert (); } break; case GNUTLS_PK_RSA: if (pk_params->params_nr >= 6) rc = gcry_sexp_build (&s_key, NULL, "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))", pk_params->params[0], pk_params->params[1], pk_params->params[2], pk_params->params[3], pk_params->params[4], pk_params->params[5]); else { gnutls_assert (); } break; default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } if (rc != 0) { gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } /* put the data into a simple list */ if (gcry_sexp_build (&s_hash, NULL, "%m", hash)) { gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } /* pass it to libgcrypt */ rc = gcry_pk_sign (&s_sig, s_hash, s_key); if (rc != 0) { gnutls_assert (); ret = GNUTLS_E_PK_SIGN_FAILED; goto cleanup; } ret = GNUTLS_E_INTERNAL_ERROR; switch (algo) { case GNUTLS_PK_DSA: { list = gcry_sexp_find_token (s_sig, "r", 0); if (list == NULL) { gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } res[0] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); list = gcry_sexp_find_token (s_sig, "s", 0); if (list == NULL) { gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } res[1] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); ret = _gnutls_encode_ber_rs (signature, res[0], res[1]); if (ret < 0) { gnutls_assert (); goto cleanup; } } break; case GNUTLS_PK_RSA: { list = gcry_sexp_find_token (s_sig, "s", 0); if (list == NULL) { gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } res[0] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); ret = _gnutls_mpi_dprint (res[0], signature); if (ret < 0) { gnutls_assert (); goto cleanup; } } break; default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: _gnutls_mpi_release (&hash); if (res[0]) _gnutls_mpi_release (&res[0]); if (res[1]) _gnutls_mpi_release (&res[1]); if (s_sig) gcry_sexp_release (s_sig); if (s_hash) gcry_sexp_release (s_hash); if (s_key) gcry_sexp_release (s_key); 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; 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; }
/* 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; }
int _gnutls_proc_dh_common_client_kx (gnutls_session_t session, opaque * data, size_t _data_size, mpi_t g, mpi_t p) { uint16_t n_Y; size_t _n_Y; int ret; ssize_t data_size = _data_size; DECR_LEN (data_size, 2); n_Y = _gnutls_read_uint16 (&data[0]); _n_Y = n_Y; DECR_LEN (data_size, n_Y); if (_gnutls_mpi_scan_nz (&session->key->client_Y, &data[2], &_n_Y)) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } _gnutls_dh_set_peer_public (session, session->key->client_Y); session->key->KEY = gnutls_calc_dh_key (session->key->client_Y, session->key->dh_secret, p); if (session->key->KEY == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_mpi_release (&session->key->client_Y); _gnutls_mpi_release (&session->key->dh_secret); if (_gnutls_cipher_suite_get_kx_algo (&session->security_parameters.current_cipher_suite) != GNUTLS_KX_DHE_PSK) { ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY); } else /* In DHE_PSK the key is set differently */ { gnutls_datum tmp_dh_key; ret = _gnutls_mpi_dprint (&tmp_dh_key, session->key->KEY); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_set_psk_session_key (session, &tmp_dh_key); _gnutls_free_datum (&tmp_dh_key); } _gnutls_mpi_release (&session->key->KEY); if (ret < 0) { return ret; } return 0; }
/* return A = g^a % N */ int _gnutls_gen_srp_client_kx (gnutls_session_t session, opaque ** data) { size_t n_a; int ret; uint8_t *data_a; char *username, *password; char buf[64]; gnutls_srp_client_credentials_t cred; cred = (gnutls_srp_client_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_SRP, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (session->internals.srp_username == NULL) { username = cred->username; password = cred->password; } else { username = session->internals.srp_username; password = session->internals.srp_password; } if (username == NULL || password == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* calc A = g^a % N */ if (G == NULL || N == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } A = _gnutls_calc_srp_A (&_a, G, N); if (A == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* Rest of SRP calculations */ /* calculate u */ session->key->u = _gnutls_calc_srp_u (A, B, N); if (session->key->u == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_dump_mpi ("SRP U: ", session->key->u); /* S = (B - g^x) ^ (a + u * x) % N */ S = _gnutls_calc_srp_S2 (B, G, session->key->x, _a, session->key->u, N); if (S == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_dump_mpi ("SRP B: ", B); _gnutls_mpi_release (&_b); _gnutls_mpi_release (&V); _gnutls_mpi_release (&session->key->u); _gnutls_mpi_release (&B); ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY); _gnutls_mpi_release (&S); if (ret < 0) { gnutls_assert(); return ret; } if (_gnutls_mpi_print (NULL, &n_a, A) != 0) { gnutls_assert (); return GNUTLS_E_MPI_PRINT_FAILED; } (*data) = gnutls_malloc (n_a + 2); if ((*data) == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* copy A */ data_a = (*data); if (_gnutls_mpi_print (&data_a[2], &n_a, A) != 0) { gnutls_free (*data); return GNUTLS_E_MPI_PRINT_FAILED; } _gnutls_hard_log ("INT: SRP A[%d]: %s\n", n_a, _gnutls_bin2hex (&data_a[2], n_a, buf, sizeof (buf))); _gnutls_mpi_release (&A); _gnutls_write_uint16 (n_a, data_a); return n_a + 2; }
/* return A = g^a % N */ int _gnutls_gen_srp_client_kx(gnutls_session_t session, gnutls_buffer_st * data) { int ret; char *username, *password; gnutls_srp_client_credentials_t cred; extension_priv_data_t epriv; srp_ext_st *priv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SRP, &epriv); if (ret < 0) { /* peer didn't send a username */ gnutls_assert(); return GNUTLS_E_UNKNOWN_SRP_USERNAME; } priv = epriv; cred = (gnutls_srp_client_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_SRP); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (priv->username == NULL) { username = cred->username; password = cred->password; } else { username = priv->username; password = priv->password; } if (username == NULL || password == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* calc A = g^a % N */ if (G == NULL || N == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } A = _gnutls_calc_srp_A(&_a, G, N); if (A == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } /* Rest of SRP calculations */ /* calculate u */ session->key.u = _gnutls_calc_srp_u(A, B, N); if (session->key.u == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } _gnutls_mpi_log("SRP U: ", session->key.u); /* S = (B - g^x) ^ (a + u * x) % N */ S = _gnutls_calc_srp_S2(B, G, session->key.x, _a, session->key.u, N); if (S == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } _gnutls_mpi_log("SRP B: ", B); zrelease_temp_mpi_key(&_b); zrelease_temp_mpi_key(&V); zrelease_temp_mpi_key(&session->key.u); zrelease_temp_mpi_key(&B); ret = _gnutls_mpi_dprint(session->key.srp_key, &session->key.key); zrelease_temp_mpi_key(&S); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_buffer_append_mpi(data, 16, A, 0); if (ret < 0) return gnutls_assert_val(ret); _gnutls_mpi_log("SRP A: ", A); _gnutls_mpi_release(&A); return data->length; }
/* just read A and put it to session */ int _gnutls_proc_srp_client_kx (gnutls_session_t session, opaque * data, size_t _data_size) { size_t _n_A; ssize_t data_size = _data_size; int ret; DECR_LEN (data_size, 2); _n_A = _gnutls_read_uint16 (&data[0]); DECR_LEN (data_size, _n_A); if (_gnutls_mpi_scan_nz (&A, &data[2], &_n_A) || A == NULL) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } _gnutls_dump_mpi ("SRP A: ", A); _gnutls_dump_mpi ("SRP B: ", B); /* Checks if A % n == 0. */ if ((ret = check_a_mod_n (A, N)) < 0) { gnutls_assert (); return ret; } /* Start the SRP calculations. * - Calculate u */ session->key->u = _gnutls_calc_srp_u (A, B, N); if (session->key->u == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_dump_mpi ("SRP U: ", session->key->u); /* S = (A * v^u) ^ b % N */ S = _gnutls_calc_srp_S1 (A, _b, session->key->u, V, N); if (S == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_dump_mpi ("SRP S: ", S); _gnutls_mpi_release (&A); _gnutls_mpi_release (&_b); _gnutls_mpi_release (&V); _gnutls_mpi_release (&session->key->u); _gnutls_mpi_release (&B); ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY); _gnutls_mpi_release (&S); if (ret < 0) { gnutls_assert (); return ret; } return 0; }
/* The internal version of export */ static int _get_sk_rsa_raw (gnutls_openpgp_privkey_t pkey, gnutls_openpgp_keyid_t keyid, gnutls_datum_t * m, gnutls_datum_t * e, gnutls_datum_t * d, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * u) { int pk_algorithm, ret, i; cdk_packet_t pkt; uint32_t kid32[2]; bigint_t params[MAX_PRIV_PARAMS_SIZE]; int params_size = MAX_PRIV_PARAMS_SIZE; if (pkey == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } KEYID_IMPORT (kid32, keyid); pkt = _gnutls_openpgp_find_key (pkey->knode, kid32, 1); if (pkt == NULL) { gnutls_assert (); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } pk_algorithm = _gnutls_openpgp_get_algo (pkt->pkt.secret_key->pk->pubkey_algo); if (pk_algorithm != GNUTLS_PK_RSA) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } ret = _gnutls_openpgp_privkey_get_mpis (pkey, kid32, params, ¶ms_size); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_mpi_dprint (params[0], m); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = _gnutls_mpi_dprint (params[1], e); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (m); goto cleanup; } ret = _gnutls_mpi_dprint (params[2], d); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (m); _gnutls_free_datum (e); goto cleanup; } ret = _gnutls_mpi_dprint (params[3], p); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (m); _gnutls_free_datum (e); _gnutls_free_datum (d); goto cleanup; } ret = _gnutls_mpi_dprint (params[4], q); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (m); _gnutls_free_datum (e); _gnutls_free_datum (d); _gnutls_free_datum (p); goto cleanup; } ret = _gnutls_mpi_dprint (params[5], u); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (q); _gnutls_free_datum (m); _gnutls_free_datum (e); _gnutls_free_datum (d); _gnutls_free_datum (p); goto cleanup; } ret = 0; cleanup: for (i = 0; i < params_size; i++) { _gnutls_mpi_release (¶ms[i]); } return ret; }
/** * gnutls_x509_privkey_export_dsa_raw - This function will export the DSA private key * @params: a structure that holds the DSA parameters * @p: will hold the p * @q: will hold the q * @g: will hold the g * @y: will hold the y * @x: will hold the x * * This function will export the DSA private key's parameters found in the given * structure. The new parameters will be allocated using * gnutls_malloc() and will be stored in the appropriate datum. * **/ int gnutls_x509_privkey_export_dsa_raw (gnutls_x509_privkey_t key, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * g, gnutls_datum_t * y, gnutls_datum_t * x) { int ret; if (key == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* P */ ret = _gnutls_mpi_dprint (p, key->params[0]); if (ret < 0) { gnutls_assert (); return ret; } /* Q */ ret = _gnutls_mpi_dprint (q, key->params[1]); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (p); return ret; } /* G */ ret = _gnutls_mpi_dprint (g, key->params[2]); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (p); _gnutls_free_datum (q); return ret; } /* Y */ ret = _gnutls_mpi_dprint (y, key->params[3]); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (p); _gnutls_free_datum (g); _gnutls_free_datum (q); return ret; } /* X */ ret = _gnutls_mpi_dprint (x, key->params[4]); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (y); _gnutls_free_datum (p); _gnutls_free_datum (g); _gnutls_free_datum (q); return ret; } return 0; }
/* 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; }