/** * gnutls_openpgp_crt_verify_ring: * @key: the structure that holds the key. * @keyring: holds the keyring to check against * @flags: unused (should be 0) * @verify: will hold the certificate verification output. * * Verify all signatures in the key, using the given set of keys * (keyring). * * The key verification output will be put in @verify and will be one * or more of the #gnutls_certificate_status_t enumerated elements * bitwise or'd. * * %GNUTLS_CERT_INVALID: A signature on the key is invalid. * * %GNUTLS_CERT_REVOKED: The key has been revoked. * * Note that this function does not verify using any "web of trust". * You may use GnuPG for that purpose, or any other external PGP * application. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_crt_verify_ring (gnutls_openpgp_crt_t key, gnutls_openpgp_keyring_t keyring, unsigned int flags, unsigned int *verify) { gnutls_openpgp_keyid_t id; cdk_error_t rc; int status; if (!key || !keyring) { gnutls_assert (); return GNUTLS_E_NO_CERTIFICATE_FOUND; } *verify = 0; rc = cdk_pk_check_sigs (key->knode, keyring->db, &status); if (rc == CDK_Error_No_Key) { rc = GNUTLS_E_NO_CERTIFICATE_FOUND; gnutls_assert (); return rc; } else if (rc != CDK_Success) { _gnutls_x509_log ("cdk_pk_check_sigs: error %d\n", rc); rc = _gnutls_map_cdk_rc (rc); gnutls_assert (); return rc; } _gnutls_x509_log ("status: %x\n", status); if (status & CDK_KEY_INVALID) *verify |= GNUTLS_CERT_INVALID; if (status & CDK_KEY_REVOKED) *verify |= GNUTLS_CERT_REVOKED; if (status & CDK_KEY_NOSIGNER) *verify |= GNUTLS_CERT_SIGNER_NOT_FOUND; /* Check if the key is included in the ring. */ if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME)) { rc = gnutls_openpgp_crt_get_key_id (key, id); if (rc < 0) { gnutls_assert (); return rc; } rc = gnutls_openpgp_keyring_check_id (keyring, id, 0); /* If it exists in the keyring don't treat it as unknown. */ if (rc == 0 && *verify & GNUTLS_CERT_SIGNER_NOT_FOUND) *verify ^= GNUTLS_CERT_SIGNER_NOT_FOUND; } return 0; }
/** * gnutls_openpgp_privkey_set_preferred_key_id: * @key: the structure that contains the OpenPGP public key. * @keyid: the selected keyid * * This allows setting a preferred key id for the given certificate. * This key will be used by functions that involve key handling. * * Returns: On success, 0 is returned, or an error code. **/ int gnutls_openpgp_privkey_set_preferred_key_id (gnutls_openpgp_privkey_t key, const gnutls_openpgp_keyid_t keyid) { int ret; if (!key) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* check if the id is valid */ ret = gnutls_openpgp_privkey_get_subkey_idx (key, keyid); if (ret < 0) { _gnutls_x509_log ("the requested subkey does not exist\n"); gnutls_assert (); return ret; } key->preferred_set = 1; memcpy (key->preferred_keyid, keyid, sizeof (gnutls_openpgp_keyid_t)); return 0; }
int _gnutls_openpgp_get_algo (int cdk_algo) { int algo; if (is_RSA (cdk_algo)) algo = GNUTLS_PK_RSA; else if (is_DSA (cdk_algo)) algo = GNUTLS_PK_DSA; else { _gnutls_x509_log ("Unknown OpenPGP algorithm %d\n", cdk_algo); algo = GNUTLS_PK_UNKNOWN; } return algo; }
/** * gnutls_x509_dn_import: get opaque DN object from DER RDN sequence * @dn: the structure that will hold the imported DN * @data: should contain a DER encoded RDN sequence * * This function parses an RDN sequence and stores the result to a * #gnutls_x509_dn_t structure. The structure must have been initialized * with gnutls_x509_dn_init(). You may use gnutls_x509_dn_get_rdn_ava() to * decode the DN. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. * * Since: 2.4.0 **/ int gnutls_x509_dn_import (gnutls_x509_dn_t dn, const gnutls_datum_t * data) { int result; char err[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; result = asn1_der_decoding ((ASN1_TYPE *) &dn, data->data, data->size, err); if (result != ASN1_SUCCESS) { /* couldn't decode DER */ _gnutls_x509_log ("ASN.1 Decoding error: %s\n", err); gnutls_assert (); return _gnutls_asn2err (result); } return 0; }
/** * gnutls_pkcs12_import: * @pkcs12: The structure to store the parsed PKCS12. * @data: The DER or PEM encoded PKCS12. * @format: One of DER or PEM * @flags: an ORed sequence of gnutls_privkey_pkcs8_flags * * This function will convert the given DER or PEM encoded PKCS12 * to the native gnutls_pkcs12_t format. The output will be stored in 'pkcs12'. * * If the PKCS12 is PEM encoded it should have a header of "PKCS12". * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_import (gnutls_pkcs12_t pkcs12, const gnutls_datum_t * data, gnutls_x509_crt_fmt_t format, unsigned int flags) { int result = 0, need_free = 0; gnutls_datum_t _data; char error_str[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; _data.data = data->data; _data.size = data->size; if (pkcs12 == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* If the PKCS12 is in PEM format then decode it */ if (format == GNUTLS_X509_FMT_PEM) { opaque *out; result = _gnutls_fbase64_decode (PEM_PKCS12, data->data, data->size, &out); if (result <= 0) { if (result == 0) result = GNUTLS_E_INTERNAL_ERROR; gnutls_assert (); return result; } _data.data = out; _data.size = result; need_free = 1; } result = asn1_der_decoding (&pkcs12->pkcs12, _data.data, _data.size, error_str); if (result != ASN1_SUCCESS) { result = _gnutls_asn2err (result); _gnutls_x509_log ("DER error: %s\n", error_str); gnutls_assert (); goto cleanup; } if (need_free) _gnutls_free_datum (&_data); return 0; cleanup: if (need_free) _gnutls_free_datum (&_data); return result; }
/* Writes the digest information and the digest in a DER encoded * structure. The digest info is allocated and stored into the info structure. */ static int encode_ber_digest_info (gnutls_digest_algorithm_t hash, const gnutls_datum_t * digest, gnutls_datum_t * info) { ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; int result; const char *algo; algo = _gnutls_x509_mac_to_oid ((gnutls_mac_algorithm_t) hash); if (algo == NULL) { gnutls_assert (); _gnutls_x509_log ("Hash algorithm: %d\n", hash); return GNUTLS_E_UNKNOWN_PK_ALGORITHM; } if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), "GNUTLS.DigestInfo", &dinfo)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } result = asn1_write_value (dinfo, "digestAlgorithm.algorithm", algo, 1); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&dinfo); return _gnutls_asn2err (result); } /* Write an ASN.1 NULL in the parameters field. This matches RFC 3279 and RFC 4055, although is arguable incorrect from a historic perspective (see those documents for more information). Regardless of what is correct, this appears to be what most implementations do. */ result = asn1_write_value (dinfo, "digestAlgorithm.parameters", ASN1_NULL, ASN1_NULL_SIZE); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&dinfo); return _gnutls_asn2err (result); } result = asn1_write_value (dinfo, "digest", digest->data, digest->size); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&dinfo); return _gnutls_asn2err (result); } info->size = 0; asn1_der_coding (dinfo, "", NULL, &info->size, NULL); info->data = gnutls_malloc (info->size); if (info->data == NULL) { gnutls_assert (); asn1_delete_structure (&dinfo); return GNUTLS_E_MEMORY_ERROR; } result = asn1_der_coding (dinfo, "", info->data, &info->size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&dinfo); return _gnutls_asn2err (result); } asn1_delete_structure (&dinfo); return 0; }
/* receive the key exchange message ( n, g, s, B) */ int _gnutls_proc_srp_server_kx (gnutls_session_t session, opaque * data, size_t _data_size) { uint8_t n_s; uint16_t n_g, n_n, n_b; size_t _n_s, _n_g, _n_n, _n_b; const uint8_t *data_n; const uint8_t *data_g; const uint8_t *data_s; const uint8_t *data_b; int i, ret; opaque hd[SRP_MAX_HASH_SIZE]; char *username, *password; ssize_t data_size = _data_size; 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; } i = 0; /* Read N */ DECR_LEN (data_size, 2); n_n = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_n); data_n = &data[i]; i += n_n; /* Read G */ DECR_LEN (data_size, 2); n_g = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_g); data_g = &data[i]; i += n_g; /* Read salt */ DECR_LEN (data_size, 1); n_s = data[i]; i += 1; DECR_LEN (data_size, n_s); data_s = &data[i]; i += n_s; /* Read B */ DECR_LEN (data_size, 2); n_b = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_b); data_b = &data[i]; i += n_b; _n_s = n_s; _n_g = n_g; _n_n = n_n; _n_b = n_b; if (_gnutls_mpi_scan_nz (&N, data_n, &_n_n) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_scan_nz (&G, data_g, &_n_g) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_scan_nz (&B, data_b, &_n_b) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } /* Check if the g and n are from the SRP * draft. Otherwise check if N is a prime and G * a generator. */ if ((ret = check_g_n (data_g, _n_g, data_n, _n_n)) < 0) { _gnutls_x509_log ("Checking the SRP group parameters.\n"); if ((ret = group_check_g_n (G, N)) < 0) { gnutls_assert (); return ret; } } /* Checks if b % n == 0 */ if ((ret = check_b_mod_n (B, N)) < 0) { gnutls_assert (); return ret; } /* generate x = SHA(s | SHA(U | ":" | p)) * (or the equivalent using bcrypt) */ if ((ret = _gnutls_calc_srp_x (username, password, (opaque *) data_s, n_s, &_n_g, hd)) < 0) { gnutls_assert (); return ret; } if (_gnutls_mpi_scan_nz (&session->key->x, hd, &_n_g) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } return i; /* return the processed data * needed in auth_srp_rsa. */ }
/** * gnutls_dh_params_import_pkcs3 - import DH params from a pkcs3 structure * @params: A structure where the parameters will be copied to * @pkcs3_params: should contain a PKCS3 DHParams structure PEM or DER encoded * @format: the format of params. PEM or DER. * * This function will extract the DHParams found in a PKCS3 formatted * structure. This is the format generated by "openssl dhparam" tool. * * If the structure is PEM encoded, it should have a header * of "BEGIN DH PARAMETERS". * * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned, * otherwise an error code is returned. **/ int gnutls_dh_params_import_pkcs3 (gnutls_dh_params_t params, const gnutls_datum_t * pkcs3_params, gnutls_x509_crt_fmt_t format) { ASN1_TYPE c2; int result, need_free = 0; gnutls_datum_t _params; if (format == GNUTLS_X509_FMT_PEM) { opaque *out; result = _gnutls_fbase64_decode ("DH PARAMETERS", pkcs3_params->data, pkcs3_params->size, &out); if (result <= 0) { if (result == 0) result = GNUTLS_E_INTERNAL_ERROR; gnutls_assert (); return result; } _params.data = out; _params.size = result; need_free = 1; } else { _params.data = pkcs3_params->data; _params.size = pkcs3_params->size; } if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), "GNUTLS.DHParameter", &c2)) != ASN1_SUCCESS) { gnutls_assert (); if (need_free != 0) { gnutls_free (_params.data); _params.data = NULL; } return _gnutls_asn2err (result); } result = asn1_der_decoding (&c2, _params.data, _params.size, NULL); if (need_free != 0) { gnutls_free (_params.data); _params.data = NULL; } if (result != ASN1_SUCCESS) { /* couldn't decode DER */ _gnutls_x509_log ("DHParams: Decoding error %d\n", result); gnutls_assert (); asn1_delete_structure (&c2); return _gnutls_asn2err (result); } /* Read PRIME */ result = _gnutls_x509_read_int (c2, "prime", ¶ms->params[0]); if (result < 0) { asn1_delete_structure (&c2); gnutls_assert (); return result; } /* read the generator */ result = _gnutls_x509_read_int (c2, "base", ¶ms->params[1]); if (result < 0) { asn1_delete_structure (&c2); _gnutls_mpi_release (¶ms->params[0]); gnutls_assert (); return result; } asn1_delete_structure (&c2); return 0; }
/* the same as _gnutls_handshake_sign_cert_vrfy except that it is made for TLS 1.2 */ static int _gnutls_handshake_sign_cert_vrfy12 (gnutls_session_t session, gnutls_cert * cert, gnutls_privkey * pkey, gnutls_datum_t * signature) { gnutls_datum_t dconcat; int ret; opaque concat[MAX_SIG_SIZE]; digest_hd_st td; gnutls_sign_algorithm_t sign_algo; gnutls_digest_algorithm_t hash_algo; digest_hd_st *handshake_td; handshake_td = &session->internals.handshake_mac_handle.tls12.sha1; hash_algo = handshake_td->algorithm; sign_algo = _gnutls_x509_pk_to_sign (cert->subject_pk_algorithm, hash_algo); /* The idea here is to try signing with the one of the algorithms * that have been initiated at handshake (SHA1, SHA256). If they * are not requested by peer... tough luck */ ret = _gnutls_session_sign_algo_requested (session, sign_algo); if (sign_algo == GNUTLS_SIGN_UNKNOWN || ret < 0) { handshake_td = &session->internals.handshake_mac_handle.tls12.sha256; hash_algo = handshake_td->algorithm; sign_algo = _gnutls_x509_pk_to_sign (cert->subject_pk_algorithm, hash_algo); if (sign_algo == GNUTLS_SIGN_UNKNOWN) { gnutls_assert (); return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM; } ret = _gnutls_session_sign_algo_requested (session, sign_algo); if (ret < 0) { gnutls_assert (); _gnutls_x509_log ("Server did not allow either '%s' or '%s' for signing\n", gnutls_mac_get_name (hash_algo), gnutls_mac_get_name (session->internals.handshake_mac_handle. tls12.sha1.algorithm)); return ret; } } _gnutls_x509_log ("sign handshake cert vrfy: picked %s with %s\n", gnutls_sign_algorithm_get_name (sign_algo), gnutls_mac_get_name (hash_algo)); ret = _gnutls_hash_copy (&td, handshake_td); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_hash_deinit (&td, concat); dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); ret = _gnutls_tls_sign (session, cert, pkey, &dconcat, signature); if (ret < 0) { gnutls_assert (); return ret; } return sign_algo; }
/* Reads and returns the PK algorithm of the given certificate-like * ASN.1 structure. src_name should be something like "tbsCertificate.subjectPublicKeyInfo". */ int _gnutls_x509_get_pk_algorithm (ASN1_TYPE src, const char *src_name, unsigned int *bits) { int result; opaque *str = NULL; int algo; char oid[64]; int len; bigint_t params[MAX_PUBLIC_PARAMS_SIZE]; char name[128]; _asnstr_append_name (name, sizeof (name), src_name, ".algorithm.algorithm"); len = sizeof (oid); result = asn1_read_value (src, name, oid, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } algo = _gnutls_x509_oid2pk_algorithm (oid); if (algo == GNUTLS_PK_UNKNOWN) { _gnutls_x509_log ("%s: unknown public key algorithm: %s\n", __func__, oid); } if (bits == NULL) { return algo; } /* Now read the parameters' bits */ _asnstr_append_name (name, sizeof (name), src_name, ".subjectPublicKey"); len = 0; result = asn1_read_value (src, name, NULL, &len); if (result != ASN1_MEM_ERROR) { gnutls_assert (); return _gnutls_asn2err (result); } if (len % 8 != 0) { gnutls_assert (); return GNUTLS_E_CERTIFICATE_ERROR; } len /= 8; str = gnutls_malloc (len); if (str == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _asnstr_append_name (name, sizeof (name), src_name, ".subjectPublicKey"); result = asn1_read_value (src, name, str, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); gnutls_free (str); return _gnutls_asn2err (result); } len /= 8; switch (algo) { case GNUTLS_PK_RSA: { if ((result = _gnutls_x509_read_rsa_params (str, len, params)) < 0) { gnutls_assert (); return result; } bits[0] = _gnutls_mpi_get_nbits (params[0]); _gnutls_mpi_release (¶ms[0]); _gnutls_mpi_release (¶ms[1]); } break; case GNUTLS_PK_DSA: { if ((result = _gnutls_x509_read_dsa_pubkey (str, len, params)) < 0) { gnutls_assert (); return result; } bits[0] = _gnutls_mpi_get_nbits (params[3]); _gnutls_mpi_release (¶ms[3]); } break; } gnutls_free (str); return algo; }
/* Reads the digest information. * we use DER here, although we should use BER. It works fine * anyway. */ static int decode_ber_digest_info (const gnutls_datum_t * info, gnutls_mac_algorithm_t * hash, opaque * digest, int *digest_size) { ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; int result; char str[1024]; int len; if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), "GNUTLS.DigestInfo", &dinfo)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } result = asn1_der_decoding (&dinfo, info->data, info->size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&dinfo); return _gnutls_asn2err (result); } len = sizeof (str) - 1; result = asn1_read_value (dinfo, "digestAlgorithm.algorithm", str, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&dinfo); return _gnutls_asn2err (result); } *hash = _gnutls_x509_oid2mac_algorithm (str); if (*hash == GNUTLS_MAC_UNKNOWN) { _gnutls_x509_log ("verify.c: HASH OID: %s\n", str); gnutls_assert (); asn1_delete_structure (&dinfo); return GNUTLS_E_UNKNOWN_ALGORITHM; } len = sizeof (str) - 1; result = asn1_read_value (dinfo, "digestAlgorithm.parameters", str, &len); /* To avoid permitting garbage in the parameters field, either the parameters field is not present, or it contains 0x05 0x00. */ if (!(result == ASN1_ELEMENT_NOT_FOUND || (result == ASN1_SUCCESS && len == ASN1_NULL_SIZE && memcmp (str, ASN1_NULL, ASN1_NULL_SIZE) == 0))) { gnutls_assert (); asn1_delete_structure (&dinfo); return GNUTLS_E_ASN1_GENERIC_ERROR; } result = asn1_read_value (dinfo, "digest", digest, digest_size); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&dinfo); return _gnutls_asn2err (result); } asn1_delete_structure (&dinfo); return 0; }
/* Parses an X509 DN in the asn1_struct, and puts the output into * the string buf. The output is an LDAP encoded DN. * * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence". * That is to point in the rndSequence. */ int _gnutls_x509_parse_dn (ASN1_TYPE asn1_struct, const char *asn1_rdn_name, char *buf, size_t * sizeof_buf) { gnutls_string out_str; int k2, k1, result; char tmpbuffer1[MAX_NAME_SIZE]; char tmpbuffer2[MAX_NAME_SIZE]; char tmpbuffer3[MAX_NAME_SIZE]; opaque value[MAX_STRING_LEN], *value2 = NULL; char *escaped = NULL; const char *ldap_desc; char oid[128]; int len, printable; char *string = NULL; size_t sizeof_string, sizeof_escaped; if (sizeof_buf == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (buf) buf[0] = 0; else *sizeof_buf = 0; _gnutls_string_init (&out_str, gnutls_malloc, gnutls_realloc, gnutls_free); k1 = 0; do { k1++; /* create a string like "tbsCertList.issuer.rdnSequence.?1" */ if (asn1_rdn_name[0]!=0) snprintf( tmpbuffer1, sizeof (tmpbuffer1), "%s.?%u", asn1_rdn_name, k1); else snprintf( tmpbuffer1, sizeof (tmpbuffer1), "?%u", k1); len = sizeof (value) - 1; result = asn1_read_value (asn1_struct, tmpbuffer1, value, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { break; } if (result != ASN1_VALUE_NOT_FOUND) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } k2 = 0; do { /* Move to the attibute type and values */ k2++; if (tmpbuffer1[0] != 0) snprintf( tmpbuffer2, sizeof (tmpbuffer2), "%s.?%u", tmpbuffer1, k2); else snprintf( tmpbuffer2, sizeof (tmpbuffer2), "?%u", k2); /* Try to read the RelativeDistinguishedName attributes. */ len = sizeof (value) - 1; result = asn1_read_value (asn1_struct, tmpbuffer2, value, &len); if (result == ASN1_ELEMENT_NOT_FOUND) break; if (result != ASN1_VALUE_NOT_FOUND) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* Read the OID */ _gnutls_str_cpy (tmpbuffer3, sizeof (tmpbuffer3), tmpbuffer2); _gnutls_str_cat (tmpbuffer3, sizeof (tmpbuffer3), ".type"); len = sizeof (oid) - 1; result = asn1_read_value (asn1_struct, tmpbuffer3, oid, &len); if (result == ASN1_ELEMENT_NOT_FOUND) break; else if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* Read the Value */ _gnutls_str_cpy (tmpbuffer3, sizeof (tmpbuffer3), tmpbuffer2); _gnutls_str_cat (tmpbuffer3, sizeof (tmpbuffer3), ".value"); len = 0; result = asn1_read_value (asn1_struct, tmpbuffer3, NULL, &len); value2 = gnutls_malloc (len); if (value2 == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } result = asn1_read_value (asn1_struct, tmpbuffer3, value2, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } #define STR_APPEND(y) if ((result=_gnutls_string_append_str( &out_str, y)) < 0) { \ gnutls_assert(); \ goto cleanup; \ } /* The encodings of adjoining RelativeDistinguishedNames are separated * by a comma character (',' ASCII 44). */ /* Where there is a multi-valued RDN, the outputs from adjoining * AttributeTypeAndValues are separated by a plus ('+' ASCII 43) * character. */ if (k1 != 1) { /* the first time do not append a comma */ if (k2 != 1) { /* adjoining multi-value RDN */ STR_APPEND ("+"); } else { STR_APPEND (","); } } ldap_desc = oid2ldap_string (oid); printable = _gnutls_x509_oid_data_printable (oid); sizeof_escaped = 2 * len + 1; escaped = gnutls_malloc (sizeof_escaped); if (escaped == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } sizeof_string = 2 * len + 2; /* in case it is not printable */ string = gnutls_malloc (sizeof_string); if (string == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } STR_APPEND (ldap_desc); STR_APPEND ("="); if (printable) result = _gnutls_x509_oid_data2string (oid, value2, len, string, &sizeof_string); else result = _gnutls_x509_data2hex (value2, len, string, &sizeof_string); if (result < 0) { gnutls_assert (); _gnutls_x509_log ("Found OID: '%s' with value '%s'\n", oid, _gnutls_bin2hex (value2, len, escaped, sizeof_escaped)); goto cleanup; } STR_APPEND (str_escape (string, escaped, sizeof_escaped)); gnutls_free (string); string = NULL; gnutls_free (escaped); escaped = NULL; gnutls_free (value2); value2 = NULL; } while (1); } while (1); if (out_str.length >= (unsigned int) *sizeof_buf) { gnutls_assert (); *sizeof_buf = out_str.length + 1; result = GNUTLS_E_SHORT_MEMORY_BUFFER; goto cleanup; } if (buf) { memcpy (buf, out_str.data, out_str.length); buf[out_str.length] = 0; } *sizeof_buf = out_str.length; result = 0; cleanup: gnutls_free (value2); gnutls_free (string); gnutls_free (escaped); _gnutls_string_clear (&out_str); return result; }
/* Decodes the PKCS #7 signed data, and returns an ASN1_TYPE, * which holds them. If raw is non null then the raw decoded * data are copied (they are locally allocated) there. */ static int _decode_pkcs7_signed_data (ASN1_TYPE pkcs7, ASN1_TYPE * sdata, gnutls_datum_t * raw) { char oid[MAX_OID_SIZE]; ASN1_TYPE c2; opaque *tmp = NULL; int tmp_size, len, result; len = sizeof (oid) - 1; result = asn1_read_value (pkcs7, "contentType", oid, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } if (strcmp (oid, SIGNED_DATA_OID) != 0) { gnutls_assert (); _gnutls_x509_log ("Unknown PKCS7 Content OID '%s'\n", oid); return GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE; } if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.pkcs-7-SignedData", &c2)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } /* the Signed-data has been created, so * decode them. */ tmp_size = 0; result = asn1_read_value (pkcs7, "content", NULL, &tmp_size); if (result != ASN1_MEM_ERROR) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } tmp = gnutls_malloc (tmp_size); if (tmp == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } result = asn1_read_value (pkcs7, "content", tmp, &tmp_size); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* tmp, tmp_size hold the data and the size of the CertificateSet structure * actually the ANY stuff. */ /* Step 1. In case of a signed structure extract certificate set. */ result = asn1_der_decoding (&c2, tmp, tmp_size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } if (raw == NULL) { gnutls_free (tmp); } else { raw->data = tmp; raw->size = tmp_size; } *sdata = c2; return 0; cleanup: if (c2) asn1_delete_structure (&c2); gnutls_free (tmp); return result; }
/* This will encode and write the AttributeTypeAndValue field. * 'multi' must be zero if writing an AttributeTypeAndValue, and 1 if Attribute. * In all cases only one value is written. */ int _gnutls_x509_encode_and_write_attribute (const char *given_oid, ASN1_TYPE asn1_struct, const char *where, const void *_data, int sizeof_data, int multi) { const char *val_name; const opaque *data = _data; char tmp[128]; ASN1_TYPE c2; int result; /* Find how to encode the data. */ val_name = asn1_find_structure_from_oid (_gnutls_get_pkix (), given_oid); if (val_name == NULL) { gnutls_assert (); _gnutls_x509_log ("Cannot find OID: %s\n", given_oid); return GNUTLS_E_X509_UNSUPPORTED_OID; } _gnutls_str_cpy (tmp, sizeof (tmp), "PKIX1."); _gnutls_str_cat (tmp, sizeof (tmp), val_name); result = asn1_create_element (_gnutls_get_pkix (), tmp, &c2); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } tmp[0] = 0; if ((result = _gnutls_x509_oid_data_choice (given_oid)) > 0) { const char *string_type; int i; string_type = "printableString"; /* Check if the data is plain ascii, and use * the UTF8 string type if not. */ for (i = 0; i < sizeof_data; i++) { if (!isascii (data[i])) { string_type = "utf8String"; break; } } /* if the type is a CHOICE then write the * type we'll use. */ result = asn1_write_value (c2, "", string_type, 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto error; } _gnutls_str_cpy (tmp, sizeof (tmp), string_type); } result = asn1_write_value (c2, tmp, data, sizeof_data); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto error; } /* write the data (value) */ _gnutls_str_cpy (tmp, sizeof (tmp), where); _gnutls_str_cat (tmp, sizeof (tmp), ".value"); if (multi != 0) { /* if not writing an AttributeTypeAndValue, but an Attribute */ _gnutls_str_cat (tmp, sizeof (tmp), "s"); /* values */ result = asn1_write_value (asn1_struct, tmp, "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto error; } _gnutls_str_cat (tmp, sizeof (tmp), ".?LAST"); } result = _gnutls_x509_der_encode_and_copy (c2, "", asn1_struct, tmp, 0); if (result < 0) { gnutls_assert (); result = _gnutls_asn2err (result); goto error; } /* write the type */ _gnutls_str_cpy (tmp, sizeof (tmp), where); _gnutls_str_cat (tmp, sizeof (tmp), ".type"); result = asn1_write_value (asn1_struct, tmp, given_oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto error; } result = 0; error: asn1_delete_structure (&c2); return result; }
/* Decodes the SafeContents, and puts the output in * the given bag. */ int _pkcs12_decode_safe_contents (const gnutls_datum_t * content, gnutls_pkcs12_bag_t bag) { char oid[MAX_OID_SIZE], root[ASN1_MAX_NAME_SIZE]; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; int len, result; int bag_type; gnutls_datum_t attr_val; int count = 0, i, attributes, j; size_t size; /* Step 1. Extract the SEQUENCE. */ if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.pkcs-12-SafeContents", &c2)) != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_der_decoding (&c2, content->data, content->size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* Count the number of bags */ result = asn1_number_of_elements (c2, "", &count); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } bag->bag_elements = MIN (MAX_BAG_ELEMENTS, count); for (i = 0; i < bag->bag_elements; i++) { snprintf (root, sizeof (root), "?%u.bagId", i + 1); len = sizeof (oid); result = asn1_read_value (c2, root, oid, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* Read the Bag type */ bag_type = oid2bag (oid); if (bag_type < 0) { gnutls_assert (); goto cleanup; } /* Read the Bag Value */ snprintf (root, sizeof (root), "?%u.bagValue", i + 1); result = _gnutls_x509_read_value (c2, root, &bag->element[i].data, 0); if (result < 0) { gnutls_assert (); goto cleanup; } if (bag_type == GNUTLS_BAG_CERTIFICATE || bag_type == GNUTLS_BAG_CRL || bag_type == GNUTLS_BAG_SECRET) { gnutls_datum_t tmp = bag->element[i].data; result = _pkcs12_decode_crt_bag (bag_type, &tmp, &bag->element[i].data); if (result < 0) { gnutls_assert (); goto cleanup; } _gnutls_free_datum (&tmp); } /* read the bag attributes */ snprintf (root, sizeof (root), "?%u.bagAttributes", i + 1); result = asn1_number_of_elements (c2, root, &attributes); if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } if (attributes < 0) attributes = 1; if (result != ASN1_ELEMENT_NOT_FOUND) for (j = 0; j < attributes; j++) { snprintf (root, sizeof (root), "?%u.bagAttributes.?%u", i + 1, j + 1); result = _gnutls_x509_decode_and_read_attribute (c2, root, oid, sizeof (oid), &attr_val, 1, 0); if (result < 0) { gnutls_assert (); continue; /* continue in case we find some known attributes */ } if (strcmp (oid, KEY_ID_OID) == 0) { size = attr_val.size; result = _gnutls_x509_decode_octet_string (NULL, attr_val.data, size, attr_val.data, &size); attr_val.size = size; if (result < 0) { _gnutls_free_datum (&attr_val); gnutls_assert (); _gnutls_x509_log ("Error decoding PKCS12 Bag Attribute OID '%s'\n", oid); continue; } bag->element[i].local_key_id = attr_val; } else if (strcmp (oid, FRIENDLY_NAME_OID) == 0) { size = attr_val.size; result = _gnutls_x509_decode_octet_string ("BMPString", attr_val.data, size, attr_val.data, &size); attr_val.size = size; if (result < 0) { _gnutls_free_datum (&attr_val); gnutls_assert (); _gnutls_x509_log ("Error decoding PKCS12 Bag Attribute OID '%s'\n", oid); continue; } bag->element[i].friendly_name = ucs2_to_ascii (attr_val.data, attr_val.size); } else { _gnutls_free_datum (&attr_val); _gnutls_x509_log ("Unknown PKCS12 Bag Attribute OID '%s'\n", oid); } } bag->element[i].type = bag_type; } asn1_delete_structure (&c2); return 0; cleanup: if (c2) asn1_delete_structure (&c2); return result; }
/* This function will convert an attribute value, specified by the OID, * to a string. The result will be a null terminated string. * * res may be null. This will just return the res_size, needed to * hold the string. */ int _gnutls_x509_oid_data2string (const char *oid, void *value, int value_size, char *res, size_t * res_size) { char str[MAX_STRING_LEN], tmpname[128]; const char *ANAME = NULL; int CHOICE = -1, len = -1, result; ASN1_TYPE tmpasn = ASN1_TYPE_EMPTY; char asn1_err[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = ""; if (value == NULL || value_size <= 0 || res_size == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (_gnutls_x509_oid_data_printable (oid) == 0) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } ANAME = _gnutls_x509_oid2asn_string (oid); CHOICE = _gnutls_x509_oid_data_choice (oid); if (ANAME == NULL) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } if ((result = asn1_create_element (_gnutls_get_pkix (), ANAME, &tmpasn)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } if ((result = asn1_der_decoding (&tmpasn, value, value_size, asn1_err)) != ASN1_SUCCESS) { gnutls_assert (); _gnutls_x509_log ("asn1_der_decoding: %s:%s\n", str, asn1_err); asn1_delete_structure (&tmpasn); return _gnutls_asn2err (result); } /* If this is a choice then we read the choice. Otherwise it * is the value; */ len = sizeof (str) - 1; if ((result = asn1_read_value (tmpasn, "", str, &len)) != ASN1_SUCCESS) { /* CHOICE */ gnutls_assert (); asn1_delete_structure (&tmpasn); return _gnutls_asn2err (result); } if (CHOICE == 0) { str[len] = 0; /* Refuse to deal with strings containing NULs. */ if (strlen (str) != len) return GNUTLS_E_ASN1_DER_ERROR; if (res) _gnutls_str_cpy (res, *res_size, str); *res_size = len; asn1_delete_structure (&tmpasn); } else { /* CHOICE */ int non_printable = 0, teletex = 0; str[len] = 0; /* Note that we do not support strings other than * UTF-8 (thus ASCII as well). */ if (strcmp (str, "printableString") != 0 && strcmp (str, "ia5String") != 0 && strcmp (str, "utf8String") != 0) { non_printable = 1; } if (strcmp (str, "teletexString") == 0) teletex = 1; _gnutls_str_cpy (tmpname, sizeof (tmpname), str); len = sizeof (str) - 1; if ((result = asn1_read_value (tmpasn, tmpname, str, &len)) != ASN1_SUCCESS) { asn1_delete_structure (&tmpasn); return _gnutls_asn2err (result); } asn1_delete_structure (&tmpasn); if (teletex != 0) { int ascii = 0, i; /* HACK: if the teletex string contains only ascii * characters then treat it as printable. */ for (i = 0; i < len; i++) if (!isascii (str[i])) ascii = 1; if (ascii == 0) non_printable = 0; } if (non_printable == 0) { str[len] = 0; /* Refuse to deal with strings containing NULs. */ if (strlen (str) != len) return GNUTLS_E_ASN1_DER_ERROR; if (res) _gnutls_str_cpy (res, *res_size, str); *res_size = len; } else { result = _gnutls_x509_data2hex (str, len, res, res_size); if (result < 0) { gnutls_assert (); return result; } } } return 0; }
/* Decodes the PKCS #12 auth_safe, and returns the allocated raw data, * which holds them. Returns an ASN1_TYPE of authenticatedSafe. */ static int _decode_pkcs12_auth_safe (ASN1_TYPE pkcs12, ASN1_TYPE * authen_safe, gnutls_datum_t * raw) { char oid[MAX_OID_SIZE]; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; gnutls_datum_t auth_safe = { NULL, 0 }; int len, result; char error_str[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; len = sizeof (oid) - 1; result = asn1_read_value (pkcs12, "authSafe.contentType", oid, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } if (strcmp (oid, DATA_OID) != 0) { gnutls_assert (); _gnutls_x509_log ("Unknown PKCS12 Content OID '%s'\n", oid); return GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE; } /* Step 1. Read the content data */ result = _gnutls_x509_read_value (pkcs12, "authSafe.content", &auth_safe, 1); if (result < 0) { gnutls_assert (); goto cleanup; } /* Step 2. Extract the authenticatedSafe. */ if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.pkcs-12-AuthenticatedSafe", &c2)) != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_der_decoding (&c2, auth_safe.data, auth_safe.size, error_str); if (result != ASN1_SUCCESS) { gnutls_assert (); _gnutls_x509_log ("DER error: %s\n", error_str); result = _gnutls_asn2err (result); goto cleanup; } if (raw == NULL) { _gnutls_free_datum (&auth_safe); } else { raw->data = auth_safe.data; raw->size = auth_safe.size; } if (authen_safe) *authen_safe = c2; else asn1_delete_structure (&c2); return 0; cleanup: if (c2) asn1_delete_structure (&c2); _gnutls_free_datum (&auth_safe); return result; }
int _gnutls_proc_rsa_client_kx (gnutls_session_t session, opaque * data, size_t _data_size) { gnutls_datum_t plaintext; gnutls_datum_t ciphertext; int ret, dsize; bigint_t *params; int params_len; int randomize_key = 0; ssize_t data_size = _data_size; if (gnutls_protocol_get_version (session) == GNUTLS_SSL3) { /* SSL 3.0 */ ciphertext.data = data; ciphertext.size = data_size; } else { /* TLS 1.0 */ DECR_LEN (data_size, 2); ciphertext.data = &data[2]; dsize = _gnutls_read_uint16 (data); if (dsize != data_size) { gnutls_assert (); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } ciphertext.size = dsize; } ret = _gnutls_get_private_rsa_params (session, ¶ms, ¶ms_len); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, params_len, 2); /* btype==2 */ if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) { /* In case decryption fails then don't inform * the peer. Just use a random key. (in order to avoid * attack against pkcs-1 formating). */ gnutls_assert (); _gnutls_x509_log ("auth_rsa: Possible PKCS #1 format attack\n"); randomize_key = 1; } else { /* If the secret was properly formatted, then * check the version number. */ if (_gnutls_get_adv_version_major (session) != plaintext.data[0] || _gnutls_get_adv_version_minor (session) != plaintext.data[1]) { /* No error is returned here, if the version number check * fails. We proceed normally. * That is to defend against the attack described in the paper * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima, * Ondej Pokorny and Tomas Rosa. */ gnutls_assert (); _gnutls_x509_log ("auth_rsa: Possible PKCS #1 version check format attack\n"); } } if (randomize_key != 0) { 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; } /* we do not need strong random numbers here. */ ret = _gnutls_rnd (GNUTLS_RND_NONCE, session->key->key.data, session->key->key.size); if (ret < 0) { gnutls_assert (); return ret; } } else { session->key->key.data = plaintext.data; session->key->key.size = plaintext.size; } /* This is here to avoid the version check attack * discussed above. */ session->key->key.data[0] = _gnutls_get_adv_version_major (session); session->key->key.data[1] = _gnutls_get_adv_version_minor (session); return 0; }