/* Do PKCS-1 RSA decryption. * params is modulus, public exp., private key * Can decrypt block type 1 and type 2 packets. */ int _gnutls_pkcs1_rsa_decrypt (gnutls_datum_t * plaintext, const gnutls_datum_t * ciphertext, mpi_t * params, unsigned params_len, unsigned btype) { unsigned k, i; int ret; mpi_t c, res; opaque *edata; size_t esize, mod_bits; mod_bits = _gnutls_mpi_get_nbits (params[0]); k = mod_bits / 8; if (mod_bits % 8 != 0) k++; esize = ciphertext->size; if (esize != k) { gnutls_assert (); return GNUTLS_E_PK_DECRYPTION_FAILED; } if (_gnutls_mpi_scan_nz (&c, ciphertext->data, &esize) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } /* we can use btype to see if the private key is * available. */ if (btype == 2) ret = _gnutls_pk_decrypt (GCRY_PK_RSA, &res, c, params, params_len); else { ret = _gnutls_pk_encrypt (GCRY_PK_RSA, &res, c, params, params_len); } _gnutls_mpi_release (&c); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_mpi_print (NULL, &esize, res); edata = gnutls_alloca (esize + 1); if (edata == NULL) { gnutls_assert (); _gnutls_mpi_release (&res); return GNUTLS_E_MEMORY_ERROR; } _gnutls_mpi_print (&edata[1], &esize, res); _gnutls_mpi_release (&res); /* EB = 00||BT||PS||00||D * (use block type 'btype') * * From now on, return GNUTLS_E_DECRYPTION_FAILED on errors, to * avoid attacks similar to the one described by Bleichenbacher in: * "Chosen Ciphertext Attacks against Protocols Based on RSA * Encryption Standard PKCS #1". */ edata[0] = 0; esize++; if (edata[0] != 0 || edata[1] != btype) { gnutls_assert (); gnutls_afree (edata); return GNUTLS_E_DECRYPTION_FAILED; } ret = GNUTLS_E_DECRYPTION_FAILED; switch (btype) { case 2: for (i = 2; i < esize; i++) { if (edata[i] == 0) { ret = 0; break; } } break; case 1: for (i = 2; i < esize; i++) { if (edata[i] == 0 && i > 2) { ret = 0; break; } if (edata[i] != 0xff) { _gnutls_handshake_log ("PKCS #1 padding error"); /* PKCS #1 padding error. Don't use GNUTLS_E_PKCS1_WRONG_PAD here. */ break; } } break; default: gnutls_assert (); gnutls_afree (edata); break; } i++; if (ret < 0) { gnutls_assert (); gnutls_afree (edata); return GNUTLS_E_DECRYPTION_FAILED; } if (_gnutls_sset_datum (plaintext, &edata[i], esize - i) < 0) { gnutls_assert (); gnutls_afree (edata); return GNUTLS_E_MEMORY_ERROR; } gnutls_afree (edata); return 0; }
/* Do PKCS-1 RSA encryption. * params is modulus, public exp. */ int _gnutls_pkcs1_rsa_encrypt (gnutls_datum_t * ciphertext, const gnutls_datum_t * plaintext, mpi_t * params, unsigned params_len, unsigned btype) { unsigned int i, pad; int ret; mpi_t m, res; opaque *edata, *ps; size_t k, psize; size_t mod_bits; mod_bits = _gnutls_mpi_get_nbits (params[0]); k = mod_bits / 8; if (mod_bits % 8 != 0) k++; if (plaintext->size > k - 11) { gnutls_assert (); return GNUTLS_E_PK_ENCRYPTION_FAILED; } edata = gnutls_alloca (k); if (edata == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* EB = 00||BT||PS||00||D * (use block type 'btype') */ edata[0] = 0; edata[1] = btype; psize = k - 3 - plaintext->size; ps = &edata[2]; switch (btype) { case 2: /* using public key */ if (params_len < RSA_PUBLIC_PARAMS) { gnutls_assert (); gnutls_afree (edata); return GNUTLS_E_INTERNAL_ERROR; } if (gc_pseudo_random (ps, psize) != GC_OK) { gnutls_assert (); gnutls_afree (edata); return GNUTLS_E_RANDOM_FAILED; } for (i = 0; i < psize; i++) while (ps[i] == 0) { if (gc_pseudo_random (&ps[i], 1) != GC_OK) { gnutls_assert (); gnutls_afree (edata); return GNUTLS_E_RANDOM_FAILED; } } break; case 1: /* using private key */ if (params_len < RSA_PRIVATE_PARAMS) { gnutls_assert (); gnutls_afree (edata); return GNUTLS_E_INTERNAL_ERROR; } for (i = 0; i < psize; i++) ps[i] = 0xff; break; default: gnutls_assert (); gnutls_afree (edata); return GNUTLS_E_INTERNAL_ERROR; } ps[psize] = 0; memcpy (&ps[psize + 1], plaintext->data, plaintext->size); if (_gnutls_mpi_scan_nz (&m, edata, &k) != 0) { gnutls_assert (); gnutls_afree (edata); return GNUTLS_E_MPI_SCAN_FAILED; } gnutls_afree (edata); if (btype == 2) /* encrypt */ ret = _gnutls_pk_encrypt (GCRY_PK_RSA, &res, m, params, params_len); else /* sign */ ret = _gnutls_pk_sign (GCRY_PK_RSA, &res, m, params, params_len); _gnutls_mpi_release (&m); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_mpi_print (NULL, &psize, res); if (psize < k) { /* padding psize */ pad = k - psize; psize = k; } else if (psize == k) { pad = 0; } else { /* psize > k !!! */ /* This is an impossible situation */ gnutls_assert (); _gnutls_mpi_release (&res); return GNUTLS_E_INTERNAL_ERROR; } ciphertext->data = gnutls_malloc (psize); if (ciphertext->data == NULL) { gnutls_assert (); _gnutls_mpi_release (&res); return GNUTLS_E_MEMORY_ERROR; } _gnutls_mpi_print (&ciphertext->data[pad], &psize, res); for (i = 0; i < pad; i++) ciphertext->data[i] = 0; ciphertext->size = k; _gnutls_mpi_release (&res); return 0; }
/* Do PKCS-1 RSA encryption. * params is modulus, public exp. */ int _gnutls_pkcs1_rsa_encrypt (gnutls_datum_t * ciphertext, const gnutls_datum_t * plaintext, bigint_t * params, unsigned params_len, unsigned btype) { unsigned int i, pad; int ret; opaque *edata, *ps; size_t k, psize; size_t mod_bits; gnutls_pk_params_st pk_params; gnutls_datum to_encrypt, encrypted; for (i = 0; i < params_len; i++) pk_params.params[i] = params[i]; pk_params.params_nr = params_len; mod_bits = _gnutls_mpi_get_nbits (params[0]); k = mod_bits / 8; if (mod_bits % 8 != 0) k++; if (plaintext->size > k - 11) { gnutls_assert (); return GNUTLS_E_PK_ENCRYPTION_FAILED; } edata = gnutls_malloc (k); if (edata == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* EB = 00||BT||PS||00||D * (use block type 'btype') */ edata[0] = 0; edata[1] = btype; psize = k - 3 - plaintext->size; ps = &edata[2]; switch (btype) { case 2: /* using public key */ if (params_len < RSA_PUBLIC_PARAMS) { gnutls_assert (); gnutls_free (edata); return GNUTLS_E_INTERNAL_ERROR; } ret = _gnutls_rnd (GNUTLS_RND_RANDOM, ps, psize); if (ret < 0) { gnutls_assert (); gnutls_free (edata); return ret; } for (i = 0; i < psize; i++) while (ps[i] == 0) { ret = _gnutls_rnd (GNUTLS_RND_RANDOM, &ps[i], 1); if (ret < 0) { gnutls_assert (); gnutls_free (edata); return ret; } } break; case 1: /* using private key */ if (params_len < RSA_PRIVATE_PARAMS) { gnutls_assert (); gnutls_free (edata); return GNUTLS_E_INTERNAL_ERROR; } for (i = 0; i < psize; i++) ps[i] = 0xff; break; default: gnutls_assert (); gnutls_free (edata); return GNUTLS_E_INTERNAL_ERROR; } ps[psize] = 0; memcpy (&ps[psize + 1], plaintext->data, plaintext->size); to_encrypt.data = edata; to_encrypt.size = k; if (btype == 2) /* encrypt */ ret = _gnutls_pk_encrypt (GNUTLS_PK_RSA, &encrypted, &to_encrypt, &pk_params); else /* sign */ ret = _gnutls_pk_sign (GNUTLS_PK_RSA, &encrypted, &to_encrypt, &pk_params); gnutls_free (edata); if (ret < 0) { gnutls_assert (); return ret; } psize = encrypted.size; if (psize < k) { /* padding psize */ pad = k - psize; psize = k; } else if (psize == k) { /* pad = 0; * no need to do anything else */ ciphertext->data = encrypted.data; ciphertext->size = encrypted.size; return 0; } else { /* psize > k !!! */ /* This is an impossible situation */ gnutls_assert (); _gnutls_free_datum (&encrypted); return GNUTLS_E_INTERNAL_ERROR; } ciphertext->data = gnutls_malloc (psize); if (ciphertext->data == NULL) { gnutls_assert (); _gnutls_free_datum (&encrypted); return GNUTLS_E_MEMORY_ERROR; } memcpy (&ciphertext->data[pad], encrypted.data, encrypted.size); for (i = 0; i < pad; i++) ciphertext->data[i] = 0; ciphertext->size = k; _gnutls_free_datum (&encrypted); return 0; }
/* Do PKCS-1 RSA decryption. * params is modulus, public exp., private key * Can decrypt block type 1 and type 2 packets. */ int _gnutls_pkcs1_rsa_decrypt (gnutls_datum_t * plaintext, const gnutls_datum_t * ciphertext, bigint_t * params, unsigned params_len, unsigned btype) { unsigned int k, i; int ret; size_t esize, mod_bits; gnutls_pk_params_st pk_params; for (i = 0; i < params_len; i++) pk_params.params[i] = params[i]; pk_params.params_nr = params_len; mod_bits = _gnutls_mpi_get_nbits (params[0]); k = mod_bits / 8; if (mod_bits % 8 != 0) k++; esize = ciphertext->size; if (esize != k) { gnutls_assert (); return GNUTLS_E_PK_DECRYPTION_FAILED; } /* we can use btype to see if the private key is * available. */ if (btype == 2) { ret = _gnutls_pk_decrypt (GNUTLS_PK_RSA, plaintext, ciphertext, &pk_params); } else { ret = _gnutls_pk_encrypt (GNUTLS_PK_RSA, plaintext, ciphertext, &pk_params); } if (ret < 0) { gnutls_assert (); return ret; } /* EB = 00||BT||PS||00||D * (use block type 'btype') * * From now on, return GNUTLS_E_DECRYPTION_FAILED on errors, to * avoid attacks similar to the one described by Bleichenbacher in: * "Chosen Ciphertext Attacks against Protocols Based on RSA * Encryption Standard PKCS #1". */ if (plaintext->data[0] != 0 || plaintext->data[1] != btype) { gnutls_assert (); return GNUTLS_E_DECRYPTION_FAILED; } ret = GNUTLS_E_DECRYPTION_FAILED; switch (btype) { case 2: for (i = 2; i < plaintext->size; i++) { if (plaintext->data[i] == 0) { ret = 0; break; } } break; case 1: for (i = 2; i < plaintext->size; i++) { if (plaintext->data[i] == 0 && i > 2) { ret = 0; break; } if (plaintext->data[i] != 0xff) { _gnutls_handshake_log ("PKCS #1 padding error"); _gnutls_free_datum (plaintext); /* PKCS #1 padding error. Don't use GNUTLS_E_PKCS1_WRONG_PAD here. */ break; } } break; default: gnutls_assert (); _gnutls_free_datum (plaintext); break; } i++; if (ret < 0) { gnutls_assert (); _gnutls_free_datum (plaintext); return GNUTLS_E_DECRYPTION_FAILED; } memmove (plaintext->data, &plaintext->data[i], esize - i); plaintext->size = esize - i; return 0; }
/* return RSA(random) using the peers public key */ int _gnutls_gen_rsa_client_kx(gnutls_session_t session, gnutls_buffer_st * data) { cert_auth_info_t auth = session->key.auth_info; gnutls_datum_t sdata; /* data to send */ gnutls_pk_params_st params; int ret; if (auth == NULL) { /* this shouldn't have happened. The proc_certificate * function should have detected that. */ gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } session->key.key.size = GNUTLS_MASTER_SIZE; session->key.key.data = gnutls_malloc(session->key.key.size); if (session->key.key.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_rnd(GNUTLS_RND_RANDOM, session->key.key.data, session->key.key.size); if (ret < 0) { gnutls_assert(); return ret; } if (session->internals.rsa_pms_version[0] == 0) { session->key.key.data[0] = _gnutls_get_adv_version_major(session); session->key.key.data[1] = _gnutls_get_adv_version_minor(session); } else { /* use the version provided */ session->key.key.data[0] = session->internals.rsa_pms_version[0]; session->key.key.data[1] = session->internals.rsa_pms_version[1]; } /* move RSA parameters to key (session). */ if ((ret = _gnutls_get_public_rsa_params(session, ¶ms)) < 0) { gnutls_assert(); return ret; } ret = _gnutls_pk_encrypt(GNUTLS_PK_RSA, &sdata, &session->key.key, ¶ms); gnutls_pk_params_release(¶ms); if (ret < 0) return gnutls_assert_val(ret); if (get_num_version(session) == GNUTLS_SSL3) { /* SSL 3.0 */ _gnutls_buffer_replace_data(data, &sdata); return data->length; } else { /* TLS 1 */ ret = _gnutls_buffer_append_data_prefix(data, 16, sdata.data, sdata.size); _gnutls_free_datum(&sdata); return ret; } }
/* Generate client key exchange message * * * struct { * select (KeyExchangeAlgorithm) { * uint8_t psk_identity<0..2^16-1>; * EncryptedPreMasterSecret; * } exchange_keys; * } ClientKeyExchange; */ static int _gnutls_gen_rsa_psk_client_kx(gnutls_session_t session, gnutls_buffer_st * data) { cert_auth_info_t auth = session->key.auth_info; gnutls_datum_t sdata; /* data to send */ gnutls_pk_params_st params; gnutls_psk_client_credentials_t cred; gnutls_datum_t username, key; int ret, free; unsigned init_pos; if (auth == NULL) { /* this shouldn't have happened. The proc_certificate * function should have detected that. */ gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } gnutls_datum_t premaster_secret; premaster_secret.size = GNUTLS_MASTER_SIZE; premaster_secret.data = gnutls_malloc(premaster_secret.size); if (premaster_secret.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } /* Generate random */ ret = gnutls_rnd(GNUTLS_RND_RANDOM, premaster_secret.data, premaster_secret.size); if (ret < 0) { gnutls_assert(); return ret; } /* Set version */ if (session->internals.rsa_pms_version[0] == 0) { premaster_secret.data[0] = _gnutls_get_adv_version_major(session); premaster_secret.data[1] = _gnutls_get_adv_version_minor(session); } else { /* use the version provided */ premaster_secret.data[0] = session->internals.rsa_pms_version[0]; premaster_secret.data[1] = session->internals.rsa_pms_version[1]; } /* move RSA parameters to key (session). */ if ((ret = _gnutls_get_public_rsa_params(session, ¶ms)) < 0) { gnutls_assert(); return ret; } /* Encrypt premaster secret */ if ((ret = _gnutls_pk_encrypt(GNUTLS_PK_RSA, &sdata, &premaster_secret, ¶ms)) < 0) { gnutls_assert(); return ret; } gnutls_pk_params_release(¶ms); cred = (gnutls_psk_client_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_PSK); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } ret = _gnutls_find_psk_key(session, cred, &username, &key, &free); if (ret < 0) return gnutls_assert_val(ret); /* Here we set the PSK key */ ret = set_rsa_psk_session_key(session, &key, &premaster_secret); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Create message for client key exchange * * struct { * uint8_t psk_identity<0..2^16-1>; * EncryptedPreMasterSecret; * } */ init_pos = data->length; /* Write psk_identity and EncryptedPreMasterSecret into data stream */ ret = _gnutls_buffer_append_data_prefix(data, 16, username.data, username.size); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_buffer_append_data_prefix(data, 16, sdata.data, sdata.size); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = data->length - init_pos; cleanup: _gnutls_free_datum(&sdata); _gnutls_free_temp_key_datum(&premaster_secret); if (free) { _gnutls_free_temp_key_datum(&key); gnutls_free(username.data); } return ret; }
static int pct_test(gnutls_pk_algorithm_t algo, const gnutls_pk_params_st* params) { int ret; gnutls_datum_t sig = {NULL, 0}; const char const_data[20] = "onetwothreefourfive"; gnutls_datum_t ddata, tmp = {NULL,0}; char* gen_data = NULL; if (algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_EC) { unsigned hash_len; _gnutls_dsa_q_to_hash(algo, params, &hash_len); gen_data = gnutls_malloc(hash_len); gnutls_rnd(GNUTLS_RND_NONCE, gen_data, hash_len); ddata.data = (void*)gen_data; ddata.size = hash_len; } else { ddata.data = (void*)const_data; ddata.size = sizeof(const_data); } switch (algo) { case GNUTLS_PK_RSA: ret = _gnutls_pk_encrypt(algo, &sig, &ddata, params); if (ret < 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); goto cleanup; } if (ddata.size == sig.size && memcmp(ddata.data, sig.data, sig.size) == 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); gnutls_assert(); goto cleanup; } ret = _gnutls_pk_decrypt(algo, &tmp, &sig, params); if (ret < 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); gnutls_assert(); goto cleanup; } if (tmp.size != ddata.size || memcmp(tmp.data, ddata.data, tmp.size) != 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); gnutls_assert(); goto cleanup; } free(sig.data); sig.data = NULL; /* Here we don't know the purpose of the key. Check both * signing and encryption. */ case GNUTLS_PK_EC: /* we only do keys for ECDSA */ case GNUTLS_PK_DSA: ret = _gnutls_pk_sign(algo, &sig, &ddata, params); if (ret < 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); goto cleanup; } ret = _gnutls_pk_verify(algo, &ddata, &sig, params); if (ret < 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); gnutls_assert(); goto cleanup; } break; default: ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); goto cleanup; } ret = 0; cleanup: if (ret == GNUTLS_E_PK_GENERATION_ERROR) { _gnutls_switch_lib_state(LIB_STATE_ERROR); } gnutls_free(gen_data); gnutls_free(sig.data); gnutls_free(tmp.data); return ret; }