static void print_oneline(gnutls_buffer_st * str, gnutls_openpgp_crt_t cert) { int err, i; i = 0; do { char *dn; size_t dn_size = 0; err = gnutls_openpgp_crt_get_name(cert, i, NULL, &dn_size); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER && err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && err != GNUTLS_E_OPENPGP_UID_REVOKED) addf(str, "unknown name (%s), ", gnutls_strerror(err)); else { dn = gnutls_malloc(dn_size); if (!dn) addf(str, "unknown name (%s), ", gnutls_strerror (GNUTLS_E_MEMORY_ERROR)); else { err = gnutls_openpgp_crt_get_name(cert, i, dn, &dn_size); if (err < 0 && err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && err != GNUTLS_E_OPENPGP_UID_REVOKED) addf(str, "unknown name (%s), ", gnutls_strerror(err)); else if (err >= 0) addf(str, _("name[%d]: %s, "), i, dn); else if (err == GNUTLS_E_OPENPGP_UID_REVOKED) addf(str, _("revoked name[%d]: %s, "), i, dn); gnutls_free(dn); } } i++; } while (err >= 0); { char fpr[128]; size_t fpr_size = sizeof(fpr); int err; err = gnutls_openpgp_crt_get_fingerprint(cert, fpr, &fpr_size); if (err < 0) addf(str, "error: get_fingerprint: %s\n", gnutls_strerror(err)); else { adds(str, _("fingerprint: ")); _gnutls_buffer_hexprint(str, fpr, fpr_size); addf(str, ", "); } } { time_t tim; tim = gnutls_openpgp_crt_get_creation_time(cert); { char s[42]; size_t max = sizeof(s); struct tm t; if (gmtime_r(&tim, &t) == NULL) addf(str, "error: gmtime_r (%ld), ", (unsigned long) tim); else if (strftime (s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0) addf(str, "error: strftime (%ld), ", (unsigned long) tim); else addf(str, _("created: %s, "), s); } tim = gnutls_openpgp_crt_get_expiration_time(cert); { char s[42]; size_t max = sizeof(s); struct tm t; if (tim == 0) adds(str, _("never expires, ")); else { if (gmtime_r(&tim, &t) == NULL) addf(str, "error: gmtime_r (%ld), ", (unsigned long) tim); else if (strftime (s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0) addf(str, "error: strftime (%ld), ", (unsigned long) tim); else addf(str, _("expires: %s, "), s); } } } { unsigned int bits = 0; gnutls_pk_algorithm_t algo = gnutls_openpgp_crt_get_pk_algorithm(cert, &bits); const char *algostr = gnutls_pk_algorithm_get_name(algo); if (algostr) addf(str, _("key algorithm %s (%d bits)"), algostr, bits); else addf(str, _("unknown key algorithm (%d)"), algo); } }
/* Do PKCS-1 RSA encryption. * params is modulus, public exp. */ int _gnutls_pkcs1_rsa_encrypt (gnutls_datum_t * ciphertext, const gnutls_datum_t * plaintext, gnutls_pk_params_st * params, unsigned btype) { unsigned int i, pad; int ret; opaque *edata, *ps; size_t k, psize; size_t mod_bits; gnutls_datum_t to_encrypt, encrypted; mod_bits = _gnutls_mpi_get_nbits (params->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->params_nr < 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->params_nr < 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, params); else /* sign */ ret = _gnutls_pk_sign (GNUTLS_PK_RSA, &encrypted, &to_encrypt, 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 (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } memcpy (&ciphertext->data[pad], encrypted.data, encrypted.size); for (i = 0; i < pad; i++) ciphertext->data[i] = 0; ciphertext->size = k; ret = 0; cleanup: _gnutls_free_datum (&encrypted); return ret; }
/** * gnutls_pkcs12_simple_parse: * @p12: the PKCS#12 blob. * @password: optional password used to decrypt PKCS#12 blob, bags and keys. * @key: a structure to store the parsed private key. * @chain: the corresponding to key certificate chain * @chain_len: will be updated with the number of additional * @extra_certs: optional pointer to receive an array of additional * certificates found in the PKCS#12 blob. * @extra_certs_len: will be updated with the number of additional * certs. * @crl: an optional structure to store the parsed CRL. * @flags: should be zero * * This function parses a PKCS#12 blob in @p12blob and extracts the * private key, the corresponding certificate chain, and any additional * certificates and a CRL. * * The @extra_certs_ret and @extra_certs_ret_len parameters are optional * and both may be set to %NULL. If either is non-%NULL, then both must * be. * * MAC:ed PKCS#12 files are supported. Encrypted PKCS#12 bags are * supported. Encrypted PKCS#8 private keys are supported. However, * only password based security, and the same password for all * operations, are supported. * * The private keys may be RSA PKCS#1 or DSA private keys encoded in * the OpenSSL way. * * PKCS#12 file may contain many keys and/or certificates, and there * is no way to identify which key/certificate pair you want. You * should make sure the PKCS#12 file only contain one key/certificate * pair and/or one CRL. * * It is believed that the limitations of this function is acceptable * for most usage, and that any more flexibility would introduce * complexity that would make it harder to use this functionality at * all. * * If the provided structure has encrypted fields but no password * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1 **/ int gnutls_pkcs12_simple_parse (gnutls_pkcs12_t p12, const char *password, gnutls_x509_privkey_t * key, gnutls_x509_crt_t ** chain, unsigned int * chain_len, gnutls_x509_crt_t ** extra_certs, unsigned int * extra_certs_len, gnutls_x509_crl_t * crl, unsigned int flags) { gnutls_pkcs12_bag_t bag = NULL; gnutls_x509_crt_t *_extra_certs = NULL; unsigned int _extra_certs_len = 0; gnutls_x509_crt_t *_chain = NULL; unsigned int _chain_len = 0; int idx = 0; int ret; size_t cert_id_size = 0; size_t key_id_size = 0; opaque cert_id[20]; opaque key_id[20]; int privkey_ok = 0; *key = NULL; if (crl) *crl = NULL; /* find the first private key */ for (;;) { int elements_in_bag; int i; ret = gnutls_pkcs12_bag_init (&bag); if (ret < 0) { bag = NULL; gnutls_assert (); goto done; } ret = gnutls_pkcs12_get_bag (p12, idx, bag); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_type (bag, 0); if (ret < 0) { gnutls_assert (); goto done; } if (ret == GNUTLS_BAG_ENCRYPTED) { if (password == NULL) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto done; } ret = gnutls_pkcs12_bag_decrypt (bag, password); if (ret < 0) { gnutls_assert (); goto done; } } elements_in_bag = gnutls_pkcs12_bag_get_count (bag); if (elements_in_bag < 0) { gnutls_assert (); goto done; } for (i = 0; i < elements_in_bag; i++) { int type; gnutls_datum_t data; type = gnutls_pkcs12_bag_get_type (bag, i); if (type < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_data (bag, i, &data); if (ret < 0) { gnutls_assert (); goto done; } switch (type) { case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: if (password == NULL) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto done; } case GNUTLS_BAG_PKCS8_KEY: if (*key != NULL) /* too simple to continue */ { gnutls_assert (); break; } ret = gnutls_x509_privkey_init (key); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_privkey_import_pkcs8 (*key, &data, GNUTLS_X509_FMT_DER, password, type == GNUTLS_BAG_PKCS8_KEY ? GNUTLS_PKCS_PLAIN : 0); if (ret < 0) { gnutls_assert (); gnutls_x509_privkey_deinit (*key); goto done; } key_id_size = sizeof (key_id); ret = gnutls_x509_privkey_get_key_id (*key, 0, key_id, &key_id_size); if (ret < 0) { gnutls_assert (); gnutls_x509_privkey_deinit (*key); goto done; } privkey_ok = 1; /* break */ break; default: break; } } idx++; gnutls_pkcs12_bag_deinit (bag); if (privkey_ok != 0) /* private key was found */ break; } if (privkey_ok == 0) /* no private key */ { gnutls_assert (); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } /* now find the corresponding certificate */ idx = 0; bag = NULL; for (;;) { int elements_in_bag; int i; ret = gnutls_pkcs12_bag_init (&bag); if (ret < 0) { bag = NULL; gnutls_assert (); goto done; } ret = gnutls_pkcs12_get_bag (p12, idx, bag); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_type (bag, 0); if (ret < 0) { gnutls_assert (); goto done; } if (ret == GNUTLS_BAG_ENCRYPTED) { ret = gnutls_pkcs12_bag_decrypt (bag, password); if (ret < 0) { gnutls_assert (); goto done; } } elements_in_bag = gnutls_pkcs12_bag_get_count (bag); if (elements_in_bag < 0) { gnutls_assert (); goto done; } for (i = 0; i < elements_in_bag; i++) { int type; gnutls_datum_t data; gnutls_x509_crt_t this_cert; type = gnutls_pkcs12_bag_get_type (bag, i); if (type < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_data (bag, i, &data); if (ret < 0) { gnutls_assert (); goto done; } switch (type) { case GNUTLS_BAG_CERTIFICATE: ret = gnutls_x509_crt_init (&this_cert); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_crt_import (this_cert, &data, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); gnutls_x509_crt_deinit (this_cert); goto done; } /* check if the key id match */ cert_id_size = sizeof (cert_id); ret = gnutls_x509_crt_get_key_id (this_cert, 0, cert_id, &cert_id_size); if (ret < 0) { gnutls_assert (); gnutls_x509_crt_deinit (this_cert); goto done; } if (memcmp (cert_id, key_id, cert_id_size) != 0) { /* they don't match - skip the certificate */ if (extra_certs) { void *tmp = _extra_certs; _extra_certs = gnutls_realloc (_extra_certs, sizeof(_extra_certs[0]) * ++_extra_certs_len); if (!_extra_certs) { gnutls_assert (); gnutls_free(tmp); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _extra_certs[_extra_certs_len - 1] = this_cert; this_cert = NULL; } else { gnutls_x509_crt_deinit (this_cert); } } else { if (_chain_len == 0) { _chain = gnutls_malloc (sizeof(_chain[0]) * (++_chain_len)); if (!_chain) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _chain[_chain_len - 1] = this_cert; this_cert = NULL; } else { gnutls_x509_crt_deinit (this_cert); } } break; case GNUTLS_BAG_CRL: if (crl == NULL || *crl != NULL) { gnutls_assert (); break; } ret = gnutls_x509_crl_init (crl); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_crl_import (*crl, &data, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); gnutls_x509_crl_deinit (*crl); goto done; } break; case GNUTLS_BAG_ENCRYPTED: /* XXX Bother to recurse one level down? Unlikely to use the same password anyway. */ case GNUTLS_BAG_EMPTY: default: break; } } idx++; gnutls_pkcs12_bag_deinit (bag); } if (_chain_len != 1) { ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto done; } ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len); if (ret < 0) { gnutls_assert(); goto done; } ret = 0; done: if (bag) gnutls_pkcs12_bag_deinit (bag); if (ret < 0) { if (*key) gnutls_x509_privkey_deinit(*key); if (_extra_certs_len && _extra_certs != NULL) { unsigned int i; for (i = 0; i < _extra_certs_len; i++) gnutls_x509_crt_deinit(_extra_certs[i]); gnutls_free(_extra_certs); } if (_chain_len && _chain != NULL) { unsigned int i; for (i = 0; i < _chain_len; i++) gnutls_x509_crt_deinit(_chain[i]); gnutls_free(_chain); } } else { if (extra_certs) { *extra_certs = _extra_certs; *extra_certs_len = _extra_certs_len; } *chain = _chain; *chain_len = _chain_len; } return ret; }
/* Writes the value of the datum in the given ASN1_TYPE. If str is non * zero it encodes it as OCTET STRING. */ int _gnutls_x509_write_value (ASN1_TYPE c, const char *root, const gnutls_datum_t * data, int str) { int result; int asize; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; gnutls_datum_t val; asize = data->size + 16; val.data = gnutls_malloc (asize); if (val.data == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } if (str) { /* Convert it to OCTET STRING */ if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.pkcs-7-Data", &c2)) != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_write_value (c2, "", data->data, data->size); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = _gnutls_x509_der_encode (c2, "", &val, 0); if (result < 0) { gnutls_assert (); goto cleanup; } } else { val.data = data->data; val.size = data->size; } /* Write the data. */ result = asn1_write_value (c, root, val.data, val.size); if (val.data != data->data) _gnutls_free_datum (&val); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } return 0; cleanup: if (val.data != data->data) _gnutls_free_datum (&val); return result; }
/* DER Encodes the src ASN1_TYPE and stores it to * the given datum. If str is non null then the data are encoded as * an OCTET STRING. */ int _gnutls_x509_der_encode (ASN1_TYPE src, const char *src_name, gnutls_datum_t * res, int str) { int size, result; int asize; opaque *data = NULL; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; size = 0; result = asn1_der_coding (src, src_name, NULL, &size, NULL); if (result != ASN1_MEM_ERROR) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* allocate data for the der */ if (str) size += 16; /* for later to include the octet tags */ asize = size; data = gnutls_malloc (size); if (data == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } result = asn1_der_coding (src, src_name, data, &size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } if (str) { if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.pkcs-7-Data", &c2)) != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_write_value (c2, "", data, size); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_der_coding (c2, "", data, &asize, NULL); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } size = asize; asn1_delete_structure (&c2); } res->data = data; res->size = size; return 0; cleanup: gnutls_free (data); asn1_delete_structure (&c2); return result; }
/* Copy datum 'src' to 'dest'. */ static void copy_datum(gnutls_datum *dest, gnutls_datum *src) { dest->size = src->size; dest->data = memcpy(gnutls_malloc(src->size), src->data, src->size); }
/** * gnutls_x509_privkey_import_openssl: * @key: The structure to store the parsed key * @data: The DER or PEM encoded key. * @password: the password to decrypt the key (if it is encrypted). * * This function will convert the given PEM encrypted to * the native gnutls_x509_privkey_t format. The * output will be stored in @key. * * The @password should be in ASCII. If the password is not provided * or wrong then %GNUTLS_E_DECRYPTION_FAILED will be returned. * * If the Certificate is PEM encoded it should have a header of * "PRIVATE KEY" and the "DEK-Info" header. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_privkey_import_openssl(gnutls_x509_privkey_t key, const gnutls_datum_t * data, const char *password) { gnutls_cipher_hd_t handle; gnutls_cipher_algorithm_t cipher = GNUTLS_CIPHER_UNKNOWN; gnutls_datum_t b64_data; gnutls_datum_t salt, enc_key; unsigned char *key_data; size_t key_data_size; const char *pem_header = (void *) data->data; const char *pem_header_start = (void *) data->data; ssize_t pem_header_size; int ret; unsigned int i, iv_size, l; pem_header_size = data->size; pem_header = memmem(pem_header, pem_header_size, "PRIVATE KEY---", 14); if (pem_header == NULL) { gnutls_assert(); return GNUTLS_E_PARSING_ERROR; } pem_header_size -= (ptrdiff_t) (pem_header - pem_header_start); pem_header = memmem(pem_header, pem_header_size, "DEK-Info: ", 10); if (pem_header == NULL) { gnutls_assert(); return GNUTLS_E_PARSING_ERROR; } pem_header_size = data->size - (ptrdiff_t) (pem_header - pem_header_start) - 10; pem_header += 10; for (i = 0; i < sizeof(pem_ciphers) / sizeof(pem_ciphers[0]); i++) { l = strlen(pem_ciphers[i].name); if (!strncmp(pem_header, pem_ciphers[i].name, l) && pem_header[l] == ',') { pem_header += l + 1; cipher = pem_ciphers[i].cipher; break; } } if (cipher == GNUTLS_CIPHER_UNKNOWN) { _gnutls_debug_log ("Unsupported PEM encryption type: %.10s\n", pem_header); gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } iv_size = gnutls_cipher_get_iv_size(cipher); salt.size = iv_size; salt.data = gnutls_malloc(salt.size); if (!salt.data) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); for (i = 0; i < salt.size * 2; i++) { unsigned char x; const char *c = &pem_header[i]; if (*c >= '0' && *c <= '9') x = (*c) - '0'; else if (*c >= 'A' && *c <= 'F') x = (*c) - 'A' + 10; else { gnutls_assert(); /* Invalid salt in encrypted PEM file */ ret = GNUTLS_E_INVALID_REQUEST; goto out_salt; } if (i & 1) salt.data[i / 2] |= x; else salt.data[i / 2] = x << 4; } pem_header += salt.size * 2; if (*pem_header != '\r' && *pem_header != '\n') { gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; goto out_salt; } while (*pem_header == '\n' || *pem_header == '\r') pem_header++; ret = _gnutls_base64_decode((const void *) pem_header, pem_header_size, &b64_data); if (ret < 0) { gnutls_assert(); goto out_salt; } if (b64_data.size < 16) { /* Just to be sure our parsing is OK */ gnutls_assert(); ret = GNUTLS_E_PARSING_ERROR; goto out_b64; } ret = GNUTLS_E_MEMORY_ERROR; enc_key.size = gnutls_cipher_get_key_size(cipher); enc_key.data = gnutls_malloc(enc_key.size); if (!enc_key.data) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto out_b64; } key_data_size = b64_data.size; key_data = gnutls_malloc(key_data_size); if (!key_data) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto out_enc_key; } while (1) { memcpy(key_data, b64_data.data, key_data_size); ret = openssl_hash_password(password, &enc_key, &salt); if (ret < 0) { gnutls_assert(); goto out; } ret = gnutls_cipher_init(&handle, cipher, &enc_key, &salt); if (ret < 0) { gnutls_assert(); gnutls_cipher_deinit(handle); goto out; } ret = gnutls_cipher_decrypt(handle, key_data, key_data_size); gnutls_cipher_deinit(handle); if (ret < 0) { gnutls_assert(); goto out; } /* We have to strip any padding to accept it. So a bit more ASN.1 parsing for us. */ if (key_data[0] == 0x30) { gnutls_datum_t key_datum; unsigned int blocksize = gnutls_cipher_get_block_size(cipher); unsigned int keylen = key_data[1]; unsigned int ofs = 2; if (keylen & 0x80) { int lenlen = keylen & 0x7f; keylen = 0; if (lenlen > 3) { gnutls_assert(); goto fail; } while (lenlen) { keylen <<= 8; keylen |= key_data[ofs++]; lenlen--; } } keylen += ofs; /* If there appears to be more padding than required, fail */ if (key_data_size - keylen > blocksize) { gnutls_assert(); goto fail; } /* If the padding bytes aren't all equal to the amount of padding, fail */ ofs = keylen; while (ofs < key_data_size) { if (key_data[ofs] != key_data_size - keylen) { gnutls_assert(); goto fail; } ofs++; } key_datum.data = key_data; key_datum.size = keylen; ret = gnutls_x509_privkey_import(key, &key_datum, GNUTLS_X509_FMT_DER); if (ret == 0) goto out; } fail: ret = GNUTLS_E_DECRYPTION_FAILED; goto out; } out: zeroize_key(key_data, key_data_size); gnutls_free(key_data); out_enc_key: _gnutls_free_key_datum(&enc_key); out_b64: gnutls_free(b64_data.data); out_salt: gnutls_free(salt.data); 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; }
/* Format: * 1 byte the credentials type * 4 bytes the size of the whole structure * DH stuff * 2 bytes the size of secret key in bits * 4 bytes the size of the prime * x bytes the prime * 4 bytes the size of the generator * x bytes the generator * 4 bytes the size of the public key * x bytes the public key * RSA stuff * 4 bytes the size of the modulus * x bytes the modulus * 4 bytes the size of the exponent * x bytes the exponent * CERTIFICATES * 4 bytes the length of the certificate list * 4 bytes the size of first certificate * x bytes the certificate * and so on... */ static int pack_certificate_auth_info (gnutls_session_t session, gnutls_datum_t * packed_session) { unsigned int pos = 0, i; int cert_size, pack_size; cert_auth_info_t info = _gnutls_get_auth_info (session); if (info == NULL && session->key->auth_info_size != 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (info) { cert_size = 4; for (i = 0; i < info->ncerts; i++) cert_size += 4 + info->raw_certificate_list[i].size; pack_size = 2 + 4 + info->dh.prime.size + 4 + info->dh.generator.size + 4 + info->dh.public_key.size + 4 + info->rsa_export.modulus.size + 4 + info->rsa_export.exponent.size + cert_size; } else pack_size = 0; packed_session->size = PACK_HEADER_SIZE + pack_size + sizeof (uint32_t); /* calculate the size and allocate the data. */ packed_session->data = gnutls_malloc (packed_session->size + MAX_SEC_PARAMS); if (packed_session->data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } packed_session->data[0] = GNUTLS_CRD_CERTIFICATE; _gnutls_write_uint32 (pack_size, &packed_session->data[PACK_HEADER_SIZE]); pos += 4 + PACK_HEADER_SIZE; if (pack_size > 0) { _gnutls_write_uint16 (info->dh.secret_bits, &packed_session->data[pos]); pos += 2; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.prime); pos += 4 + info->dh.prime.size; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.generator); pos += 4 + info->dh.generator.size; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.public_key); pos += 4 + info->dh.public_key.size; _gnutls_write_datum32 (&packed_session->data[pos], info->rsa_export.modulus); pos += 4 + info->rsa_export.modulus.size; _gnutls_write_datum32 (&packed_session->data[pos], info->rsa_export.exponent); pos += 4 + info->rsa_export.exponent.size; _gnutls_write_uint32 (info->ncerts, &packed_session->data[pos]); pos += 4; for (i = 0; i < info->ncerts; i++) { _gnutls_write_datum32 (&packed_session->data[pos], info->raw_certificate_list[i]); pos += sizeof (uint32_t) + info->raw_certificate_list[i].size; } } return 0; }
static gnutls_datum_t wrap_db_fetch (void *dbf, gnutls_datum_t key) { gnutls_datum_t res = { NULL, 0 }; int i; if (debug) success ("resume db fetch... (%d)\n", key.size); if (debug) { unsigned int i; printf ("key:\n"); for (i = 0; i < key.size; i++) { printf ("%02x ", key.data[i] & 0xFF); if ((i + 1) % 16 == 0) printf ("\n"); } printf ("\n"); } if (cache_db == NULL) return res; for (i = 0; i < TLS_SESSION_CACHE; i++) { if (key.size == cache_db[i].session_id_size && memcmp (key.data, cache_db[i].session_id, key.size) == 0) { if (debug) success ("resume db fetch... return info\n"); res.size = cache_db[i].session_data_size; res.data = gnutls_malloc (res.size); if (res.data == NULL) return res; memcpy (res.data, cache_db[i].session_data, res.size); if (debug) { unsigned int i; printf ("data:\n"); for (i = 0; i < res.size; i++) { printf ("%02x ", res.data[i] & 0xFF); if ((i + 1) % 16 == 0) printf ("\n"); } printf ("\n"); } return res; } } if (debug) success ("resume db fetch... NOT FOUND\n"); return res; }
static int server_recv(gnutls_session_t session, status_request_ext_st * priv, const uint8_t * data, size_t size) { size_t i; ssize_t data_size = size; /* minimum message is type (1) + responder_id_list (2) + request_extension (2) = 5 */ if (data_size < 5) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); /* We ignore non-ocsp CertificateStatusType. The spec is unclear what should be done. */ if (data[0] != 0x01) { gnutls_assert(); _gnutls_handshake_log("EXT[%p]: unknown status_type %d\n", session, data[0]); return 0; } DECR_LEN(data_size, 1); data++; priv->responder_id_size = _gnutls_read_uint16(data); DECR_LEN(data_size, 2); data += 2; if (data_size <= (ssize_t) (priv->responder_id_size * 2)) return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); priv->responder_id = gnutls_malloc(priv->responder_id_size * sizeof(*priv->responder_id)); if (priv->responder_id == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); for (i = 0; i < priv->responder_id_size; i++) { size_t l; DECR_LEN(data_size, 2); l = _gnutls_read_uint16(data); data += 2; DECR_LEN(data_size, l); priv->responder_id[i].data = gnutls_malloc(l); if (priv->responder_id[i].data == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); memcpy(priv->responder_id[i].data, data, l); priv->responder_id[i].size = l; data += l; } return 0; }
/* 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; }
/* If the psk flag is set, then an empty psk_identity_hint will * be inserted */ int _gnutls_dh_common_print_server_kx (gnutls_session_t session, mpi_t g, mpi_t p, opaque ** data, int psk) { mpi_t x, X; size_t n_X, n_g, n_p; int ret, data_size, pos; uint8_t *pdata; X = gnutls_calc_dh_secret (&x, g, p); if (X == NULL || x == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } session->key->dh_secret = x; _gnutls_dh_set_secret_bits (session, _gnutls_mpi_get_nbits (x)); _gnutls_mpi_print (NULL, &n_g, g); _gnutls_mpi_print (NULL, &n_p, p); _gnutls_mpi_print (NULL, &n_X, X); data_size = n_g + n_p + n_X + 6; if (psk != 0) data_size += 2; (*data) = gnutls_malloc (data_size); if (*data == NULL) { _gnutls_mpi_release (&X); return GNUTLS_E_MEMORY_ERROR; } pos = 0; pdata = *data; if (psk != 0) { _gnutls_write_uint16 (0, &pdata[pos]); pos += 2; } _gnutls_mpi_print (&pdata[pos + 2], &n_p, p); _gnutls_write_uint16 (n_p, &pdata[pos]); pos += n_p + 2; _gnutls_mpi_print (&pdata[pos + 2], &n_g, g); _gnutls_write_uint16 (n_g, &pdata[pos]); pos += n_g + 2; _gnutls_mpi_print (&pdata[pos + 2], &n_X, X); _gnutls_mpi_release (&X); _gnutls_write_uint16 (n_X, &pdata[pos]); ret = data_size; 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; }
/* Reads a certificate key from a token. */ static int read_cert_url(gnutls_certificate_credentials_t res, gnutls_privkey_t key, const char *url) { int ret; gnutls_x509_crt_t crt = NULL; gnutls_pcert_st *ccert = NULL; gnutls_str_array_t names; gnutls_datum_t t = {NULL, 0}; unsigned i, count = 0; _gnutls_str_array_init(&names); ccert = gnutls_malloc(sizeof(*ccert)*MAX_PKCS11_CERT_CHAIN); if (ccert == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = gnutls_x509_crt_init(&crt); if (ret < 0) { gnutls_assert(); goto cleanup; } if (res->pin.cb) gnutls_x509_crt_set_pin_function(crt, res->pin.cb, res->pin.data); ret = gnutls_x509_crt_import_url(crt, url, 0); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) ret = gnutls_x509_crt_import_url(crt, url, GNUTLS_PKCS11_OBJ_FLAG_LOGIN); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_get_x509_name(crt, &names); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Try to load the whole certificate chain from the PKCS #11 token */ for (i=0;i<MAX_PKCS11_CERT_CHAIN;i++) { ret = gnutls_x509_crt_check_issuer(crt, crt); if (i > 0 && ret != 0) { /* self signed */ break; } ret = gnutls_pcert_import_x509(&ccert[i], crt, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } count++; ret = _gnutls_get_raw_issuer(url, crt, &t, 0); if (ret < 0) break; gnutls_x509_crt_deinit(crt); crt = NULL; ret = gnutls_x509_crt_init(&crt); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_x509_crt_import(crt, &t, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_free(t.data); } ret = _gnutls_certificate_credential_append_keypair(res, key, names, ccert, count); if (ret < 0) { gnutls_assert(); goto cleanup; } if (crt != NULL) gnutls_x509_crt_deinit(crt); return 0; cleanup: if (crt != NULL) gnutls_x509_crt_deinit(crt); gnutls_free(t.data); _gnutls_str_array_clear(&names); gnutls_free(ccert); return ret; }
/* Format: * 1 byte the credentials type * 4 bytes the size of the whole structure * 4 bytes the size of the PSK username (x) * x bytes the PSK username * 2 bytes the size of secret key in bits * 4 bytes the size of the prime * x bytes the prime * 4 bytes the size of the generator * x bytes the generator * 4 bytes the size of the public key * x bytes the public key */ static int pack_psk_auth_info (gnutls_session_t session, gnutls_datum_t * packed_session) { psk_auth_info_t info; int pack_size, username_size = 0, pos; info = _gnutls_get_auth_info (session); if (info == NULL && session->key->auth_info_size != 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (info) { username_size = strlen (info->username) + 1; /* include the terminating null */ pack_size = username_size + 2 + 4 * 3 + info->dh.prime.size + info->dh.generator.size + info->dh.public_key.size; } else pack_size = 0; packed_session->size = PACK_HEADER_SIZE + pack_size + sizeof (uint32_t); /* calculate the size and allocate the data. */ packed_session->data = gnutls_malloc (packed_session->size + MAX_SEC_PARAMS); if (packed_session->data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } pos = 0; packed_session->data[pos] = GNUTLS_CRD_PSK; pos++; _gnutls_write_uint32 (pack_size, &packed_session->data[pos]); pos += 4; if (pack_size > 0) { _gnutls_write_uint32 (username_size, &packed_session->data[pos]); pos += 4; memcpy (&packed_session->data[pos], info->username, username_size); pos += username_size; _gnutls_write_uint16 (info->dh.secret_bits, &packed_session->data[pos]); pos += 2; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.prime); pos += 4 + info->dh.prime.size; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.generator); pos += 4 + info->dh.generator.size; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.public_key); pos += 4 + info->dh.public_key.size; } return 0; }
/** * gnutls_certificate_set_x509_key: * @res: is a #gnutls_certificate_credentials_t type. * @cert_list: contains a certificate list (path) for the specified private key * @cert_list_size: holds the size of the certificate list * @key: is a #gnutls_x509_privkey_t key * * This function sets a certificate/private key pair in the * gnutls_certificate_credentials_t type. This function may be * called more than once, in case multiple keys/certificates exist for * the server. For clients that wants to send more than their own end * entity certificate (e.g., also an intermediate CA cert) then put * the certificate chain in @cert_list. * * Note that the certificates and keys provided, can be safely deinitialized * after this function is called. * * If that function fails to load the @res type is at an undefined state, it must * not be reused to load other keys or certificates. * * Note that, this function by default returns zero on success and a negative value on error. * Since 3.5.6, when the flag %GNUTLS_CERTIFICATE_API_V2 is set using gnutls_certificate_set_flags() * it returns an index (greater or equal to zero). That index can be used to other functions to refer to the added key-pair. * * Returns: On success this functions returns zero, and otherwise a negative value on error (see above for modifying that behavior). * * Since: 2.4.0 **/ int gnutls_certificate_set_x509_key(gnutls_certificate_credentials_t res, gnutls_x509_crt_t * cert_list, int cert_list_size, gnutls_x509_privkey_t key) { int ret; gnutls_privkey_t pkey; gnutls_pcert_st *pcerts = NULL; gnutls_str_array_t names; _gnutls_str_array_init(&names); /* this should be first */ ret = gnutls_privkey_init(&pkey); if (ret < 0) { gnutls_assert(); return ret; } if (res->pin.cb) gnutls_privkey_set_pin_function(pkey, res->pin.cb, res->pin.data); ret = gnutls_privkey_import_x509(pkey, key, GNUTLS_PRIVKEY_IMPORT_COPY); if (ret < 0) { gnutls_assert(); return ret; } /* load certificates */ pcerts = gnutls_malloc(sizeof(gnutls_pcert_st) * cert_list_size); if (pcerts == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_get_x509_name(cert_list[0], &names); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pcert_import_x509_list(pcerts, cert_list, (unsigned int*)&cert_list_size, GNUTLS_X509_CRT_LIST_SORT); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_certificate_credential_append_keypair(res, pkey, names, pcerts, cert_list_size); if (ret < 0) { gnutls_assert(); goto cleanup; } res->ncerts++; /* after this point we do not deinitialize anything on failure to avoid * double freeing. We intentionally keep everything as the credentials state * is documented to be on undefined state. */ if ((ret = _gnutls_check_key_cert_match(res)) < 0) { gnutls_assert(); return ret; } CRED_RET_SUCCESS(res); cleanup: gnutls_free(pcerts); _gnutls_str_array_clear(&names); return ret; }
static int gen_rsa_export_server_kx (gnutls_session_t session, opaque ** data) { gnutls_rsa_params_t rsa_params; const bigint_t *rsa_mpis; size_t n_e, n_m; uint8_t *data_e, *data_m; int ret = 0, data_size; gnutls_cert *apr_cert_list; gnutls_privkey *apr_pkey; int apr_cert_list_length; gnutls_datum_t signature, ddata; cert_auth_info_t info; gnutls_certificate_credentials_t cred; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert (session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert (); return ret; } /* abort sending this message if we have a certificate * of 512 bits or less. */ if (apr_pkey && _gnutls_mpi_get_nbits (apr_pkey->params[0]) <= 512) { gnutls_assert (); return GNUTLS_E_INT_RET_0; } rsa_params = _gnutls_certificate_get_rsa_params (cred->rsa_params, cred->params_func, session); rsa_mpis = _gnutls_rsa_params_to_mpi (rsa_params); if (rsa_mpis == NULL) { gnutls_assert (); return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS; } if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE, sizeof (cert_auth_info_st), 0)) < 0) { gnutls_assert (); return ret; } info = _gnutls_get_auth_info (session); _gnutls_rsa_export_set_pubkey (session, rsa_mpis[1], rsa_mpis[0]); _gnutls_mpi_print (rsa_mpis[0], NULL, &n_m); _gnutls_mpi_print (rsa_mpis[1], NULL, &n_e); (*data) = gnutls_malloc (n_e + n_m + 4); if (*data == NULL) { return GNUTLS_E_MEMORY_ERROR; } data_m = &(*data)[0]; _gnutls_mpi_print (rsa_mpis[0], &data_m[2], &n_m); _gnutls_write_uint16 (n_m, data_m); data_e = &data_m[2 + n_m]; _gnutls_mpi_print (rsa_mpis[1], &data_e[2], &n_e); _gnutls_write_uint16 (n_e, data_e); data_size = n_m + n_e + 4; /* Generate the signature. */ ddata.data = *data; ddata.size = data_size; if (apr_cert_list_length > 0) { if ((ret = _gnutls_tls_sign_params (session, &apr_cert_list[0], apr_pkey, &ddata, &signature)) < 0) { gnutls_assert (); gnutls_free (*data); *data = NULL; return ret; } } else { gnutls_assert (); return data_size; /* do not put a signature - ILLEGAL! */ } *data = gnutls_realloc_fast (*data, data_size + signature.size + 2); if (*data == NULL) { _gnutls_free_datum (&signature); gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_write_datum16 (&((*data)[data_size]), signature); data_size += signature.size + 2; _gnutls_free_datum (&signature); return data_size; }
/** * gnutls_x509_trust_list_iter_get_ca: * @list: The structure of the list * @iter: A pointer to an iterator (initially the iterator should be %NULL) * @crt: where the certificate will be copied * * This function obtains a certificate in the trust list and advances the * iterator to the next certificate. The certificate returned in @crt must be * deallocated with gnutls_x509_crt_deinit(). * * When past the last element is accessed %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE * is returned and the iterator is reset. * * After use, the iterator must be deinitialized usin * gnutls_x509_trust_list_iter_deinit(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 **/ int gnutls_x509_trust_list_iter_get_ca(gnutls_x509_trust_list_t list, gnutls_x509_trust_list_iter_t *iter, gnutls_x509_crt_t *crt) { int ret; /* initialize iterator */ if (*iter == NULL) { *iter = gnutls_malloc(sizeof (struct gnutls_x509_trust_list_iter)); if (*iter == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); (*iter)->node_index = 0; (*iter)->ca_index = 0; #ifdef ENABLE_PKCS11 (*iter)->pkcs11_list = NULL; (*iter)->pkcs11_size = 0; (*iter)->pkcs11_index = 0; #endif /* Advance iterator to the first valid entry */ if (list->node[0].trusted_ca_size == 0) { ret = advance_iter(list, *iter); if (ret != 0) { gnutls_x509_trust_list_iter_deinit(*iter); *iter = NULL; *crt = NULL; return gnutls_assert_val(ret); } } } /* obtain the certificate at the current iterator position */ if ((*iter)->node_index < list->size) { ret = gnutls_x509_crt_init(crt); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_x509_crt_cpy(*crt, list->node[(*iter)->node_index].trusted_cas[(*iter)->ca_index]); if (ret < 0) { gnutls_x509_crt_deinit(*crt); return gnutls_assert_val(ret); } } #ifdef ENABLE_PKCS11 else if ( (*iter)->pkcs11_index < (*iter)->pkcs11_size) { ret = gnutls_x509_crt_init(crt); if (ret < 0) return gnutls_assert_val(ret); ret = gnutls_x509_crt_import_pkcs11(*crt, (*iter)->pkcs11_list[(*iter)->pkcs11_index]); if (ret < 0) { gnutls_x509_crt_deinit(*crt); return gnutls_assert_val(ret); } } #endif else { /* iterator is at end */ gnutls_x509_trust_list_iter_deinit(*iter); *iter = NULL; *crt = NULL; return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); } /* Move iterator to the next position. * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned if the iterator * has been moved to the end position. That is okay, we return the * certificate that we read and when this function is called again we * report GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE to our caller. */ ret = advance_iter(list, *iter); if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { gnutls_x509_crt_deinit(*crt); *crt = NULL; return gnutls_assert_val(ret); } return 0; }
/** Private function which generate private keys and certificates. * * @return 1 if keys were successfully generated, 0 otherwise */ static userpref_error_t userpref_gen_keys_and_cert(void) { userpref_error_t ret = USERPREF_E_SSL_ERROR; gnutls_x509_privkey_t root_privkey; gnutls_x509_crt_t root_cert; gnutls_x509_privkey_t host_privkey; gnutls_x509_crt_t host_cert; gnutls_global_deinit(); gnutls_global_init(); //use less secure random to speed up key generation gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM); gnutls_x509_privkey_init(&root_privkey); gnutls_x509_privkey_init(&host_privkey); gnutls_x509_crt_init(&root_cert); gnutls_x509_crt_init(&host_cert); /* generate root key */ gnutls_x509_privkey_generate(root_privkey, GNUTLS_PK_RSA, 2048, 0); gnutls_x509_privkey_generate(host_privkey, GNUTLS_PK_RSA, 2048, 0); /* generate certificates */ gnutls_x509_crt_set_key(root_cert, root_privkey); gnutls_x509_crt_set_serial(root_cert, "\x00", 1); gnutls_x509_crt_set_version(root_cert, 3); gnutls_x509_crt_set_ca_status(root_cert, 1); gnutls_x509_crt_set_activation_time(root_cert, time(NULL)); gnutls_x509_crt_set_expiration_time(root_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); gnutls_x509_crt_sign(root_cert, root_cert, root_privkey); gnutls_x509_crt_set_key(host_cert, host_privkey); gnutls_x509_crt_set_serial(host_cert, "\x00", 1); gnutls_x509_crt_set_version(host_cert, 3); gnutls_x509_crt_set_ca_status(host_cert, 0); gnutls_x509_crt_set_key_usage(host_cert, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE); gnutls_x509_crt_set_activation_time(host_cert, time(NULL)); gnutls_x509_crt_set_expiration_time(host_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); gnutls_x509_crt_sign(host_cert, root_cert, root_privkey); /* export to PEM format */ size_t root_key_export_size = 0; size_t host_key_export_size = 0; gnutls_datum_t root_key_pem = { NULL, 0 }; gnutls_datum_t host_key_pem = { NULL, 0 }; gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, NULL, &root_key_export_size); gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, NULL, &host_key_export_size); root_key_pem.data = gnutls_malloc(root_key_export_size); host_key_pem.data = gnutls_malloc(host_key_export_size); gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, root_key_pem.data, &root_key_export_size); root_key_pem.size = root_key_export_size; gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, host_key_pem.data, &host_key_export_size); host_key_pem.size = host_key_export_size; size_t root_cert_export_size = 0; size_t host_cert_export_size = 0; gnutls_datum_t root_cert_pem = { NULL, 0 }; gnutls_datum_t host_cert_pem = { NULL, 0 }; gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, NULL, &root_cert_export_size); gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, NULL, &host_cert_export_size); root_cert_pem.data = gnutls_malloc(root_cert_export_size); host_cert_pem.data = gnutls_malloc(host_cert_export_size); gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, root_cert_pem.data, &root_cert_export_size); root_cert_pem.size = root_cert_export_size; gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_export_size); host_cert_pem.size = host_cert_export_size; if (NULL != root_cert_pem.data && 0 != root_cert_pem.size && NULL != host_cert_pem.data && 0 != host_cert_pem.size) ret = USERPREF_E_SUCCESS; /* store values in config file */ userpref_set_keys_and_certs( &root_key_pem, &root_cert_pem, &host_key_pem, &host_cert_pem); gnutls_free(root_key_pem.data); gnutls_free(root_cert_pem.data); gnutls_free(host_key_pem.data); gnutls_free(host_cert_pem.data); //restore gnutls env gnutls_global_deinit(); gnutls_global_init(); return ret; }
int _gnutls_x509_crq_set_extension(gnutls_x509_crq_t crq, const char *ext_id, const gnutls_datum_t * ext_data, unsigned int critical) { unsigned char *extensions = NULL; size_t extensions_size = 0; gnutls_datum_t der; ASN1_TYPE c2; int result; result = gnutls_x509_crq_get_attribute_by_oid(crq, "1.2.840.113549.1.9.14", 0, NULL, &extensions_size); if (result == GNUTLS_E_SHORT_MEMORY_BUFFER) { extensions = gnutls_malloc(extensions_size); if (extensions == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } result = gnutls_x509_crq_get_attribute_by_oid(crq, "1.2.840.113549.1.9.14", 0, extensions, &extensions_size); } if (result < 0) { if (result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { extensions_size = 0; } else { gnutls_assert(); gnutls_free(extensions); return result; } } result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.Extensions", &c2); if (result != ASN1_SUCCESS) { gnutls_assert(); gnutls_free(extensions); return _gnutls_asn2err(result); } if (extensions_size > 0) { result = asn1_der_decoding(&c2, extensions, extensions_size, NULL); gnutls_free(extensions); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&c2); return _gnutls_asn2err(result); } } result = set_extension(c2, "", ext_id, ext_data, critical); if (result < 0) { gnutls_assert(); asn1_delete_structure(&c2); return result; } result = _gnutls_x509_der_encode(c2, "", &der, 0); asn1_delete_structure(&c2); if (result < 0) { gnutls_assert(); return result; } result = gnutls_x509_crq_set_attribute_by_oid(crq, "1.2.840.113549.1.9.14", der.data, der.size); gnutls_free(der.data); if (result < 0) { gnutls_assert(); return result; } return 0; }
static gnutls_pubkey_t create_rsa_from_modulus(unsigned char *modulus, unsigned int modulus_len, uint32_t exponent) { unsigned char exp_array[4]; uint32_t exponent_no = htonl(exponent); gnutls_pubkey_t rsa = NULL; gnutls_datum_t mod; gnutls_datum_t exp = { .data = exp_array, .size = sizeof(exp_array), }; int err; memcpy(exp_array, &exponent_no, sizeof(exp_array)); err = gnutls_pubkey_init(&rsa); if (err < 0) { fprintf(stderr, "Could not initialized public key structure : %s\n", gnutls_strerror(err)); return NULL; } mod.data = modulus; mod.size = modulus_len; err = gnutls_pubkey_import_rsa_raw(rsa, &mod, &exp); if (err < 0) { fprintf(stderr, "Could not set modulus and exponent on RSA key : %s\n", gnutls_strerror(err)); gnutls_pubkey_deinit(rsa); rsa = NULL; } return rsa; } static int asn_init() { static bool inited; int err; if (inited) return ASN1_SUCCESS; err = asn1_array2tree(tpm_asn1_tab, &_tpm_asn, NULL); if (err != ASN1_SUCCESS) { fprintf(stderr, "array2tree error: %d", err); goto cleanup; } inited = true; cleanup: return err; } static int create_tpm_manufacturer_info(const char *manufacturer, const char *tpm_model, const char *tpm_version, gnutls_datum_t *asn1) { ASN1_TYPE at = ASN1_TYPE_EMPTY; int err; err = asn_init(); if (err != ASN1_SUCCESS) { goto cleanup; } err = asn1_create_element(_tpm_asn, "TPM.TPMManufacturerInfo", &at); if (err != ASN1_SUCCESS) { fprintf(stderr, "asn1_create_element error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "tpmManufacturer.id", "2.23.133.2.1", 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "1. asn1_write_value error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "tpmManufacturer.manufacturer", manufacturer, 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "2. asn1_write_value error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "tpmModel.id", "2.23.133.2.2", 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "3. asn1_write_value error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "tpmModel.model", manufacturer, 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "4. asn1_write_value error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "tpmVersion.id", "2.23.133.2.3", 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "5. asn1_write_value error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "tpmVersion.version", manufacturer, 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "6. asn1_write_value error: %d\n", err); goto cleanup; } /* determine needed size of byte array */ asn1->size = 0; err = asn1_der_coding(at, "", NULL, (int *)&asn1->size, NULL); if (err != ASN1_MEM_ERROR) { fprintf(stderr, "1. asn1_der_coding error: %d\n", err); goto cleanup; } //fprintf(stderr, "size=%d\n", asn1->size); asn1->data = gnutls_malloc(asn1->size + 16); err = asn1_der_coding(at, "", asn1->data, (int *)&asn1->size, NULL); if (err != ASN1_SUCCESS) { fprintf(stderr, "2. asn1_der_coding error: %d\n", err); gnutls_free(asn1->data); asn1->data = NULL; goto cleanup; } #if 0 fprintf(stderr, "size=%d\n", asn1->size); unsigned int i = 0; for (i = 0; i < asn1->size; i++) { fprintf(stderr, "%02x ", asn1->data[i]); } fprintf(stderr, "\n"); #endif cleanup: asn1_delete_structure(&at); return err; }
/* 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; mpi_t params[MAX_PUBLIC_PARAMS_SIZE]; char name[128]; _gnutls_str_cpy (name, sizeof (name), src_name); _gnutls_str_cat (name, sizeof (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 (bits == NULL) { gnutls_free (str); return algo; } /* Now read the parameters' bits */ _gnutls_str_cpy (name, sizeof (name), src_name); _gnutls_str_cat (name, sizeof (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; } _gnutls_str_cpy (name, sizeof (name), src_name); _gnutls_str_cat (name, sizeof (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; if (algo == 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]); } if (algo == 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]); } gnutls_free (str); return algo; }
static int create_platf_manufacturer_info(const char *manufacturer, const char *platf_model, const char *platf_version, gnutls_datum_t *asn1) { ASN1_TYPE at = ASN1_TYPE_EMPTY; int err; err = asn_init(); if (err != ASN1_SUCCESS) { goto cleanup; } err = asn1_create_element(_tpm_asn, "TPM.PlatformManufacturerInfo", &at); if (err != ASN1_SUCCESS) { fprintf(stderr, "asn1_create_element error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "platformManufacturer.id", "2.23.133.2.4", 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "b1. asn1_write_value error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "platformManufacturer.manufacturer", manufacturer, 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "b2. asn1_write_value error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "platformModel.id", "2.23.133.2.5", 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "b3. asn1_write_value error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "platformModel.model", manufacturer, 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "b4. asn1_write_value error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "platformVersion.id", "2.23.133.2.6", 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "b5. asn1_write_value error: %d\n", err); goto cleanup; } err = asn1_write_value(at, "platformVersion.version", manufacturer, 0); if (err != ASN1_SUCCESS) { fprintf(stderr, "b6. asn1_write_value error: %d\n", err); goto cleanup; } /* determine needed size of byte array */ asn1->size = 0; err = asn1_der_coding(at, "", NULL, (int *)&asn1->size, NULL); if (err != ASN1_MEM_ERROR) { fprintf(stderr, "b1. asn1_der_coding error: %d\n", err); goto cleanup; } //fprintf(stderr, "size=%d\n", asn1->size); asn1->data = gnutls_malloc(asn1->size + 16); err = asn1_der_coding(at, "", asn1->data, (int *)&asn1->size, NULL); if (err != ASN1_SUCCESS) { fprintf(stderr, "b2. asn1_der_coding error: %d\n", err); gnutls_free(asn1->data); asn1->data = NULL; goto cleanup; } #if 0 fprintf(stderr, "size=%d\n", asn1->size); unsigned int i = 0; for (i = 0; i < asn1->size; i++) { fprintf(stderr, "%02x ", asn1->data[i]); } fprintf(stderr, "\n"); #endif cleanup: asn1_delete_structure(&at); return err; }
int proc_rsa_export_client_kx (gnutls_session_t session, uint8_t * data, size_t _data_size) { gnutls_datum_t plaintext; gnutls_datum_t ciphertext; int ret, dsize; gnutls_pk_params_st *params; 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); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, 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_audit_log (session, "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_audit_log (session, "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; }
/* Reads a DER encoded certificate list from memory and stores it to a * gnutls_cert structure. Returns the number of certificates parsed. */ static int parse_der_cert_mem(gnutls_certificate_credentials_t res, gnutls_privkey_t key, const void *input_cert, int input_cert_size) { gnutls_datum_t tmp; gnutls_x509_crt_t crt; gnutls_pcert_st *ccert; int ret; gnutls_str_array_t names; _gnutls_str_array_init(&names); ccert = gnutls_malloc(sizeof(*ccert)); if (ccert == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crt_init(&crt); if (ret < 0) { gnutls_assert(); goto cleanup; } tmp.data = (uint8_t *) input_cert; tmp.size = input_cert_size; ret = gnutls_x509_crt_import(crt, &tmp, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert(); gnutls_x509_crt_deinit(crt); goto cleanup; } ret = _gnutls_get_x509_name(crt, &names); if (ret < 0) { gnutls_assert(); gnutls_x509_crt_deinit(crt); goto cleanup; } ret = gnutls_pcert_import_x509(ccert, crt, 0); gnutls_x509_crt_deinit(crt); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_certificate_credential_append_keypair(res, key, names, ccert, 1); if (ret < 0) { gnutls_assert(); goto cleanup; } return ret; cleanup: _gnutls_str_array_clear(&names); gnutls_free(ccert); return ret; }
void _gnutls_mpi_log(const char *prefix, bigint_t a) { size_t binlen = 0; void *binbuf; size_t hexlen; char *hexbuf; int res; if (_gnutls_log_level < 2) return; res = _gnutls_mpi_print(a, NULL, &binlen); if (res < 0 && res != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert(); _gnutls_hard_log("MPI: %s can't print value (%d/%d)\n", prefix, res, (int) binlen); return; } if (binlen > 1024 * 1024) { gnutls_assert(); _gnutls_hard_log("MPI: %s too large mpi (%d)\n", prefix, (int) binlen); return; } binbuf = gnutls_malloc(binlen); if (!binbuf) { gnutls_assert(); _gnutls_hard_log("MPI: %s out of memory (%d)\n", prefix, (int) binlen); return; } res = _gnutls_mpi_print(a, binbuf, &binlen); if (res != 0) { gnutls_assert(); _gnutls_hard_log("MPI: %s can't print value (%d/%d)\n", prefix, res, (int) binlen); gnutls_free(binbuf); return; } hexlen = 2 * binlen + 1; hexbuf = gnutls_malloc(hexlen); if (!hexbuf) { gnutls_assert(); _gnutls_hard_log("MPI: %s out of memory (hex %d)\n", prefix, (int) hexlen); gnutls_free(binbuf); return; } _gnutls_bin2hex(binbuf, binlen, hexbuf, hexlen, NULL); _gnutls_hard_log("MPI: length: %d\n\t%s%s\n", (int) binlen, prefix, hexbuf); gnutls_free(hexbuf); gnutls_free(binbuf); }
/* Reads a base64 encoded certificate list from memory and stores it to * a gnutls_cert structure. Returns the number of certificate parsed. */ static int parse_pem_cert_mem(gnutls_certificate_credentials_t res, gnutls_privkey_t key, const char *input_cert, int input_cert_size) { int size; const char *ptr; gnutls_datum_t tmp; int ret, count, i; unsigned ncerts = 0; gnutls_pcert_st *pcerts = NULL; gnutls_str_array_t names; gnutls_x509_crt_t unsorted[DEFAULT_MAX_VERIFY_DEPTH]; _gnutls_str_array_init(&names); /* move to the certificate */ ptr = memmem(input_cert, input_cert_size, PEM_CERT_SEP, sizeof(PEM_CERT_SEP) - 1); if (ptr == NULL) ptr = memmem(input_cert, input_cert_size, PEM_CERT_SEP2, sizeof(PEM_CERT_SEP2) - 1); if (ptr == NULL) { gnutls_assert(); return GNUTLS_E_BASE64_DECODING_ERROR; } size = input_cert_size - (ptr - input_cert); count = 0; do { tmp.data = (void *) ptr; tmp.size = size; ret = gnutls_x509_crt_init(&unsorted[count]); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_x509_crt_import(unsorted[count], &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) { gnutls_assert(); goto cleanup; } count++; /* now we move ptr after the pem header */ ptr++; size--; /* find the next certificate (if any) */ if (size > 0) { char *ptr3; ptr3 = memmem(ptr, size, PEM_CERT_SEP, sizeof(PEM_CERT_SEP) - 1); if (ptr3 == NULL) ptr3 = memmem(ptr, size, PEM_CERT_SEP2, sizeof(PEM_CERT_SEP2) - 1); ptr = ptr3; size = input_cert_size - (ptr - input_cert); } else ptr = NULL; } while (ptr != NULL && count < DEFAULT_MAX_VERIFY_DEPTH); ret = _gnutls_get_x509_name(unsorted[0], &names); if (ret < 0) { gnutls_assert(); goto cleanup; } pcerts = gnutls_malloc(sizeof(gnutls_pcert_st) * count); if (pcerts == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ncerts = count; ret = gnutls_pcert_import_x509_list(pcerts, unsorted, &ncerts, GNUTLS_X509_CRT_LIST_SORT); if (ret < 0) { gnutls_free(pcerts); gnutls_assert(); goto cleanup; } ret = _gnutls_certificate_credential_append_keypair(res, key, names, pcerts, ncerts); if (ret < 0) { gnutls_assert(); goto cleanup; } for (i = 0; i < count; i++) gnutls_x509_crt_deinit(unsorted[i]); return ncerts; cleanup: _gnutls_str_array_clear(&names); for (i = 0; i < count; i++) gnutls_x509_crt_deinit(unsorted[i]); if (pcerts) { for (i = 0; i < count; i++) gnutls_pcert_deinit(&pcerts[i]); gnutls_free(pcerts); } return ret; }
/** * gnutls_pkcs11_copy_x509_crt: * @token_url: A PKCS #11 URL specifying a token * @crt: A certificate * @label: A name to be used for the stored data * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy a certificate into a PKCS #11 token specified by * a URL. The certificate can be marked as trusted or not. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_pkcs11_copy_x509_crt(const char *token_url, gnutls_x509_crt_t crt, const char *label, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; size_t der_size, id_size; uint8_t *der = NULL; uint8_t id[20]; struct ck_attribute a[16]; ck_object_class_t class = CKO_CERTIFICATE; ck_certificate_type_t type = CKC_X_509; ck_object_handle_t obj; int a_val; unsigned long category; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; memset(&sinfo, 0, sizeof(sinfo)); ret = pkcs11_url_to_info(token_url, &info); 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; } der_size = 0; ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, NULL, &der_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert(); goto cleanup; } der = gnutls_malloc(der_size); if (der == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0) { gnutls_assert(); goto cleanup; } id_size = sizeof(id); ret = gnutls_x509_crt_get_subject_key_id(crt, id, &id_size, NULL); if (ret < 0) { id_size = sizeof(id); ret = gnutls_x509_crt_get_key_id(crt, 0, id, &id_size); if (ret < 0) { gnutls_assert(); goto cleanup; } } /* FIXME: copy key usage flags */ a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof(class); a[1].type = CKA_ID; a[1].value = id; a[1].value_len = id_size; a[2].type = CKA_VALUE; a[2].value = der; a[2].value_len = der_size; a[3].type = CKA_TOKEN; a[3].value = (void *) &tval; a[3].value_len = sizeof(tval); a[4].type = CKA_CERTIFICATE_TYPE; a[4].value = &type; a[4].value_len = sizeof(type); a_val = 5; a[a_val].type = CKA_SUBJECT; a[a_val].value = crt->raw_dn.data; a[a_val].value_len = crt->raw_dn.size; 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_CA) { category = 2; a[a_val].type = CKA_CERTIFICATE_CATEGORY; a[a_val].value = (void *) &category; a[a_val].value_len = sizeof(category); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED) { a[a_val].type = CKA_TRUSTED; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } else { if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE) { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } else 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++; } } rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &obj); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* generated! */ ret = 0; cleanup: gnutls_free(der); pkcs11_close_session(&sinfo); return ret; }
static void print_cert(gnutls_buffer_st * str, gnutls_openpgp_crt_t cert) { int i, subkeys; int err; print_key_revoked(str, cert, -1); /* Version. */ { int version = gnutls_openpgp_crt_get_version(cert); if (version < 0) addf(str, "error: get_version: %s\n", gnutls_strerror(version)); else addf(str, _("\tVersion: %d\n"), version); } /* ID. */ print_key_id(str, cert, -1); print_key_fingerprint(str, cert); /* Names. */ i = 0; do { char *dn; size_t dn_size = 0; err = gnutls_openpgp_crt_get_name(cert, i, NULL, &dn_size); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER && err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && err != GNUTLS_E_OPENPGP_UID_REVOKED) addf(str, "error: get_name: %s\n", gnutls_strerror(err)); else { dn = gnutls_malloc(dn_size); if (!dn) addf(str, "error: malloc (%d): %s\n", (int) dn_size, gnutls_strerror (GNUTLS_E_MEMORY_ERROR)); else { err = gnutls_openpgp_crt_get_name(cert, i, dn, &dn_size); if (err < 0 && err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && err != GNUTLS_E_OPENPGP_UID_REVOKED) addf(str, "error: get_name: %s\n", gnutls_strerror(err)); else if (err >= 0) addf(str, _("\tName[%d]: %s\n"), i, dn); else if (err == GNUTLS_E_OPENPGP_UID_REVOKED) addf(str, _("\tRevoked Name[%d]: %s\n"), i, dn); gnutls_free(dn); } } i++; } while (err >= 0); print_key_times(str, cert, -1); print_key_info(str, cert, -1); print_key_usage(str, cert, -1); subkeys = gnutls_openpgp_crt_get_subkey_count(cert); if (subkeys < 0) return; for (i = 0; i < subkeys; i++) { addf(str, _("\n\tSubkey[%d]:\n"), i); print_key_revoked(str, cert, i); print_key_id(str, cert, i); print_key_times(str, cert, i); print_key_info(str, cert, i); print_key_usage(str, cert, i); } }