/*! * Get binary key ID from a key (public or private). */ static int keyid_bin(gnutls_x509_privkey_t key, gnutls_pubkey_t pubkey, dnssec_binary_t *id) { assert(key || pubkey); assert(id); // Flags can be used to enable SHA-2 since GnuTLS 3.4.7. int flags = 0; uint8_t *buffer = alloca(DNSSEC_KEYID_BINARY_SIZE); size_t size = DNSSEC_KEYID_SIZE; int r = key ? gnutls_x509_privkey_get_key_id(key, flags, buffer, &size) : gnutls_pubkey_get_key_id(pubkey, flags, buffer, &size); if (r != GNUTLS_E_SUCCESS || size != DNSSEC_KEYID_BINARY_SIZE) { return DNSSEC_INVALID_KEY_ID; } assert(size == DNSSEC_KEYID_BINARY_SIZE); r = dnssec_binary_resize(id, size); if (r != DNSSEC_EOK) { return r; } memcpy(id->data, buffer, size); return DNSSEC_EOK; }
/** * gnutls_pkcs12_simple_parse: * @p12: A pkcs12 type * @password: optional password used to decrypt the structure, bags and keys. * @key: a structure to store the parsed private key. * @chain: the corresponding to key certificate chain (may be %NULL) * @chain_len: will be updated with the number of additional (may be %NULL) * @extra_certs: optional pointer to receive an array of additional * certificates found in the PKCS12 structure (may be %NULL). * @extra_certs_len: will be updated with the number of additional * certs (may be %NULL). * @crl: an optional structure to store the parsed CRL (may be %NULL). * @flags: should be zero or one of GNUTLS_PKCS12_SP_* * * This function parses a PKCS12 structure in @pkcs12 and extracts the * private key, the corresponding certificate chain, any additional * certificates and a CRL. The structures in @key, @chain @crl, and @extra_certs * must not be initialized. * * The @extra_certs and @extra_certs_len parameters are optional * and both may be set to %NULL. If either is non-%NULL, then both must * be set. The value for @extra_certs is allocated * using gnutls_malloc(). * * Encrypted PKCS12 bags and PKCS8 private keys are supported, but * only with password based security and the same password for all * operations. * * Note that a PKCS12 structure may contain many keys and/or certificates, * and there is no way to identify which key/certificate pair you want. * For this reason this function is useful for PKCS12 files that contain * only one key/certificate pair and/or one CRL. * * If the provided structure has encrypted fields but no password * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED. * * Note that normally the chain constructed does not include self signed * certificates, to comply with TLS' requirements. If, however, the flag * %GNUTLS_PKCS12_SP_INCLUDE_SELF_SIGNED is specified then * self signed certificates will be included in the chain. * * Prior to using this function the PKCS #12 structure integrity must * be verified using gnutls_pkcs12_verify_mac(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1.0 **/ 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; uint8_t cert_id[20]; uint8_t key_id[20]; int privkey_ok = 0; unsigned int i; int elements_in_bag; *key = NULL; if (crl) *crl = NULL; /* find the first private key */ for (;;) { 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) { gnutls_pkcs12_bag_deinit(bag); bag = NULL; 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 < (unsigned)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; } FALLTHROUGH; 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(); 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(); goto done; } privkey_ok = 1; /* break */ break; default: break; } } idx++; gnutls_pkcs12_bag_deinit(bag); bag = NULL; 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 (;;) { 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) { gnutls_pkcs12_bag_deinit(bag); bag = NULL; 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 < (unsigned)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); this_cert = NULL; 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); this_cert = NULL; goto done; } if (memcmp(cert_id, key_id, cert_id_size) != 0) { /* they don't match - skip the certificate */ _extra_certs = gnutls_realloc_fast (_extra_certs, sizeof(_extra_certs [0]) * ++_extra_certs_len); if (!_extra_certs) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _extra_certs [_extra_certs_len - 1] = this_cert; this_cert = NULL; } else { if (chain && _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); this_cert = NULL; } } 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); *crl = NULL; 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); bag = NULL; } if (chain != NULL) { if (_chain_len != 1) { ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto done; } ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len, flags); 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); *key = NULL; } if (crl != NULL && *crl != NULL) { gnutls_x509_crl_deinit(*crl); *crl = NULL; } if (_extra_certs_len && _extra_certs != NULL) { for (i = 0; i < _extra_certs_len; i++) gnutls_x509_crt_deinit(_extra_certs[i]); gnutls_free(_extra_certs); } if (_chain_len && _chain != NULL) { for (i = 0; i < _chain_len; i++) gnutls_x509_crt_deinit(_chain[i]); gnutls_free(_chain); } return ret; } if (extra_certs && _extra_certs_len > 0) { *extra_certs = _extra_certs; *extra_certs_len = _extra_certs_len; } else { if (extra_certs) { *extra_certs = NULL; *extra_certs_len = 0; } for (i = 0; i < _extra_certs_len; i++) gnutls_x509_crt_deinit(_extra_certs[i]); gnutls_free(_extra_certs); } if (chain != NULL) { *chain = _chain; *chain_len = _chain_len; } return ret; }
/** * gnutls_pkcs11_copy_x509_privkey: * @token_url: A PKCS #11 URL specifying a token * @key: A private key * @label: A name to be used for the stored data * @key_usage: One of GNUTLS_KEY_* * @flags: One of GNUTLS_PKCS11_OBJ_* flags * * This function will copy a private key into a PKCS #11 token specified by * a URL. It is highly recommended flags to contain %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE * unless there is a strong reason not to. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_pkcs11_copy_x509_privkey (const char *token_url, gnutls_x509_privkey_t key, const char *label, unsigned int key_usage, unsigned int flags) { int ret; pakchois_session_t *pks; struct pkcs11_url_info info; ck_rv_t rv; size_t id_size; opaque id[20]; struct ck_attribute a[16]; ck_object_class_t class = CKO_PRIVATE_KEY; ck_object_handle_t obj; ck_key_type_t type; unsigned int tval = 1; int a_val; gnutls_pk_algorithm_t pk; gnutls_datum_t p, q, g, y, x; gnutls_datum_t m, e, d, u, exp1, exp2; ret = pkcs11_url_to_info (token_url, &info); if (ret < 0) { gnutls_assert (); return ret; } id_size = sizeof (id); ret = gnutls_x509_privkey_get_key_id (key, 0, id, &id_size); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = pkcs11_open_session (&pks, &info, SESSION_WRITE | pkcs11_obj_flags_to_int (flags)); if (ret < 0) { gnutls_assert (); return ret; } /* FIXME: copy key usage flags */ a_val = 0; a[a_val].type = CKA_CLASS; a[a_val].value = &class; a[a_val].value_len = sizeof (class); a_val++; a[a_val].type = CKA_ID; a[a_val].value = id; a[a_val].value_len = id_size; a_val++; a[a_val].type = CKA_KEY_TYPE; a[a_val].value = &type; a[a_val].value_len = sizeof (type); a_val++; a[a_val].type = CKA_TOKEN; a[a_val].value = &tval; a[a_val].value_len = sizeof (tval); a_val++; a[a_val].type = CKA_PRIVATE; a[a_val].value = &tval; a[a_val].value_len = sizeof (tval); a_val++; if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) tval = 1; else tval = 0; a[a_val].type = CKA_SENSITIVE; a[a_val].value = &tval; a[a_val].value_len = sizeof (tval); a_val++; pk = gnutls_x509_privkey_get_pk_algorithm (key); switch (pk) { case GNUTLS_PK_RSA: { ret = gnutls_x509_privkey_export_rsa_raw2 (key, &m, &e, &d, &p, &q, &u, &exp1, &exp2); if (ret < 0) { gnutls_assert (); goto cleanup; } type = CKK_RSA; a[a_val].type = CKA_MODULUS; a[a_val].value = m.data; a[a_val].value_len = m.size; a_val++; a[a_val].type = CKA_PUBLIC_EXPONENT; a[a_val].value = e.data; a[a_val].value_len = e.size; a_val++; a[a_val].type = CKA_PRIVATE_EXPONENT; a[a_val].value = d.data; a[a_val].value_len = d.size; a_val++; a[a_val].type = CKA_PRIME_1; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_PRIME_2; a[a_val].value = q.data; a[a_val].value_len = q.size; a_val++; a[a_val].type = CKA_COEFFICIENT; a[a_val].value = u.data; a[a_val].value_len = u.size; a_val++; a[a_val].type = CKA_EXPONENT_1; a[a_val].value = exp1.data; a[a_val].value_len = exp1.size; a_val++; a[a_val].type = CKA_EXPONENT_2; a[a_val].value = exp2.data; a[a_val].value_len = exp2.size; a_val++; break; } case GNUTLS_PK_DSA: { ret = gnutls_x509_privkey_export_dsa_raw (key, &p, &q, &g, &y, &x); if (ret < 0) { gnutls_assert (); goto cleanup; } type = CKK_DSA; a[a_val].type = CKA_PRIME; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_SUBPRIME; a[a_val].value = q.data; a[a_val].value_len = q.size; a_val++; a[a_val].type = CKA_BASE; a[a_val].value = g.data; a[a_val].value_len = g.size; a_val++; a[a_val].type = CKA_VALUE; a[a_val].value = x.data; a[a_val].value_len = x.size; a_val++; break; } default: gnutls_assert (); ret = GNUTLS_E_INVALID_REQUEST; goto cleanup; } rv = pakchois_create_object (pks, a, a_val, &obj); if (rv != CKR_OK) { gnutls_assert (); _gnutls_debug_log ("pkcs11: %s\n", pakchois_error (rv)); ret = pkcs11_rv_to_err (rv); goto cleanup; } /* generated! */ switch (pk) { case GNUTLS_PK_RSA: { gnutls_free (m.data); gnutls_free (e.data); gnutls_free (d.data); gnutls_free (p.data); gnutls_free (q.data); gnutls_free (u.data); gnutls_free (exp1.data); gnutls_free (exp2.data); break; } case GNUTLS_PK_DSA: { gnutls_free (p.data); gnutls_free (q.data); gnutls_free (g.data); gnutls_free (y.data); gnutls_free (x.data); break; } default: gnutls_assert (); ret = GNUTLS_E_INVALID_REQUEST; goto cleanup; } ret = 0; cleanup: pakchois_close_session (pks); return ret; }
/** * gnutls_pkcs11_copy_x509_privkey2: * @token_url: A PKCS #11 URL specifying a token * @key: A private key * @label: A name to be used for the stored data * @cid: The CKA_ID to set for the object -if NULL, the ID will be derived from the public key * @key_usage: One of GNUTLS_KEY_* * @flags: One of GNUTLS_PKCS11_OBJ_* flags * * This function will copy a private key into a PKCS #11 token specified by * a URL. It is highly recommended flags to contain %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE * unless there is a strong reason not to. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 **/ int gnutls_pkcs11_copy_x509_privkey2(const char *token_url, gnutls_x509_privkey_t key, const char *label, const gnutls_datum_t *cid, unsigned int key_usage, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; size_t id_size; uint8_t id[20]; struct ck_attribute a[32]; ck_object_class_t class = CKO_PRIVATE_KEY; ck_object_handle_t ctx; ck_key_type_t type; int a_val; gnutls_pk_algorithm_t pk; gnutls_datum_t p, q, g, y, x; gnutls_datum_t m, e, d, u, exp1, exp2; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; memset(&p, 0, sizeof(p)); memset(&q, 0, sizeof(q)); memset(&g, 0, sizeof(g)); memset(&y, 0, sizeof(y)); memset(&x, 0, sizeof(x)); memset(&m, 0, sizeof(m)); memset(&e, 0, sizeof(e)); memset(&d, 0, sizeof(d)); memset(&u, 0, sizeof(u)); memset(&exp1, 0, sizeof(exp1)); memset(&exp2, 0, sizeof(exp2)); ret = pkcs11_url_to_info(token_url, &info, 0); if (ret < 0) { gnutls_assert(); return ret; } ret = pkcs11_open_session(&sinfo, NULL, info, SESSION_WRITE | pkcs11_obj_flags_to_int(flags)); p11_kit_uri_free(info); if (ret < 0) { gnutls_assert(); return ret; } pk = gnutls_x509_privkey_get_pk_algorithm(key); FIX_KEY_USAGE(pk, key_usage); /* FIXME: copy key usage flags */ a_val = 0; a[a_val].type = CKA_CLASS; a[a_val].value = &class; a[a_val].value_len = sizeof(class); a_val++; a[a_val].type = CKA_ID; if (cid == NULL || cid->size == 0) { id_size = sizeof(id); ret = gnutls_x509_privkey_get_key_id(key, 0, id, &id_size); if (ret < 0) { p11_kit_uri_free(info); gnutls_assert(); return ret; } a[a_val].value = id; a[a_val].value_len = id_size; } else { a[a_val].value = cid->data; a[a_val].value_len = cid->size; } a_val++; a[a_val].type = CKA_SIGN; if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) { a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); } else { a[a_val].value = (void*)&fval; a[a_val].value_len = sizeof(fval); } a_val++; if (pk == GNUTLS_PK_RSA) { a[a_val].type = CKA_DECRYPT; if (key_usage & (GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_DECIPHER_ONLY)) { a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); } else { a[a_val].value = (void*)&fval; a[a_val].value_len = sizeof(fval); } a_val++; } a[a_val].type = CKA_TOKEN; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; /* a private key is set always as private unless * requested otherwise */ if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } else { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH) { a[a_val].type = CKA_ALWAYS_AUTHENTICATE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_EXTRACTABLE) { a[a_val].type = CKA_EXTRACTABLE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); (a_val)++; } else { a[a_val].type = CKA_EXTRACTABLE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); (a_val)++; } if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) { a[a_val].type = CKA_SENSITIVE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } else { a[a_val].type = CKA_SENSITIVE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } switch (pk) { case GNUTLS_PK_RSA: { ret = gnutls_x509_privkey_export_rsa_raw2(key, &m, &e, &d, &p, &q, &u, &exp1, &exp2); if (ret < 0) { gnutls_assert(); goto cleanup; } type = CKK_RSA; skip_leading_zeros(&m); skip_leading_zeros(&e); skip_leading_zeros(&d); skip_leading_zeros(&p); skip_leading_zeros(&q); skip_leading_zeros(&u); skip_leading_zeros(&exp1); skip_leading_zeros(&exp2); a[a_val].type = CKA_MODULUS; a[a_val].value = m.data; a[a_val].value_len = m.size; a_val++; a[a_val].type = CKA_PUBLIC_EXPONENT; a[a_val].value = e.data; a[a_val].value_len = e.size; a_val++; a[a_val].type = CKA_PRIVATE_EXPONENT; a[a_val].value = d.data; a[a_val].value_len = d.size; a_val++; a[a_val].type = CKA_PRIME_1; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_PRIME_2; a[a_val].value = q.data; a[a_val].value_len = q.size; a_val++; a[a_val].type = CKA_COEFFICIENT; a[a_val].value = u.data; a[a_val].value_len = u.size; a_val++; a[a_val].type = CKA_EXPONENT_1; a[a_val].value = exp1.data; a[a_val].value_len = exp1.size; a_val++; a[a_val].type = CKA_EXPONENT_2; a[a_val].value = exp2.data; a[a_val].value_len = exp2.size; a_val++; break; } case GNUTLS_PK_DSA: { ret = gnutls_x509_privkey_export_dsa_raw(key, &p, &q, &g, &y, &x); if (ret < 0) { gnutls_assert(); goto cleanup; } type = CKK_DSA; skip_leading_zeros(&p); skip_leading_zeros(&q); skip_leading_zeros(&g); skip_leading_zeros(&y); skip_leading_zeros(&x); a[a_val].type = CKA_PRIME; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_SUBPRIME; a[a_val].value = q.data; a[a_val].value_len = q.size; a_val++; a[a_val].type = CKA_BASE; a[a_val].value = g.data; a[a_val].value_len = g.size; a_val++; a[a_val].type = CKA_VALUE; a[a_val].value = x.data; a[a_val].value_len = x.size; a_val++; break; } case GNUTLS_PK_EC: { ret = _gnutls_x509_write_ecc_params(key->params.flags, &p); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_mpi_dprint(key->params. params[ECC_K], &x); if (ret < 0) { gnutls_assert(); goto cleanup; } type = CKK_ECDSA; a[a_val].type = CKA_EC_PARAMS; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_VALUE; a[a_val].value = x.data; a[a_val].value_len = x.size; a_val++; break; } default: gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; goto cleanup; } a[a_val].type = CKA_KEY_TYPE; a[a_val].value = &type; a[a_val].value_len = sizeof(type); a_val++; rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &ctx); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } ret = 0; cleanup: switch (pk) { case GNUTLS_PK_RSA: { gnutls_free(m.data); gnutls_free(e.data); gnutls_free(d.data); gnutls_free(p.data); gnutls_free(q.data); gnutls_free(u.data); gnutls_free(exp1.data); gnutls_free(exp2.data); break; } case GNUTLS_PK_DSA: { gnutls_free(p.data); gnutls_free(q.data); gnutls_free(g.data); gnutls_free(y.data); gnutls_free(x.data); break; } case GNUTLS_PK_EC: { gnutls_free(p.data); gnutls_free(x.data); break; } default: gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; break; } if (sinfo.pks != 0) pkcs11_close_session(&sinfo); return ret; }
void doit (void) { gnutls_x509_privkey_t pkey; gnutls_privkey_t abs_pkey; gnutls_x509_crq_t crq; size_t pkey_key_id_len; unsigned char *pkey_key_id = NULL; size_t crq_key_id_len; unsigned char *crq_key_id = NULL; gnutls_pk_algorithm_t algorithm; int ret; ret = global_init (); if (ret < 0) fail ("global_init: %d\n", ret); gnutls_global_set_log_function (tls_log_func); if (debug) gnutls_global_set_log_level (4711); for (algorithm = GNUTLS_PK_RSA; algorithm <= GNUTLS_PK_DSA; algorithm++) { ret = gnutls_x509_crq_init (&crq); if (ret < 0) fail ("gnutls_x509_crq_init: %d\n", ret); ret = gnutls_x509_privkey_init (&pkey); if (ret < 0) { fail ("gnutls_x509_privkey_init: %d\n", ret); } ret = gnutls_privkey_init (&abs_pkey); if (ret < 0) { fail ("gnutls_privkey_init: %d\n", ret); } ret = gnutls_x509_privkey_generate (pkey, algorithm, 1024, 0); if (ret < 0) { fail ("gnutls_x509_privkey_generate (rsa): %d\n", ret); } else if (debug) { success ("Key[%s] generation ok: %d\n", gnutls_pk_algorithm_get_name (algorithm), ret); } pkey_key_id_len = 0; ret = gnutls_x509_privkey_get_key_id (pkey, 0, pkey_key_id, &pkey_key_id_len); if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { fail ("gnutls_x509_privkey_get_key_id incorrectly returns %d\n", ret); } pkey_key_id = malloc (sizeof (unsigned char) * pkey_key_id_len); ret = gnutls_x509_privkey_get_key_id (pkey, 0, pkey_key_id, &pkey_key_id_len); if (ret != GNUTLS_E_SUCCESS) { fail ("gnutls_x509_privkey_get_key_id incorrectly returns %d\n", ret); } ret = gnutls_x509_crq_set_version (crq, 1); if (ret < 0) { fail ("gnutls_x509_crq_set_version: %d\n", ret); } ret = gnutls_x509_crq_set_key (crq, pkey); if (ret < 0) { fail ("gnutls_x509_crq_set_key: %d\n", ret); } ret = gnutls_x509_crq_set_dn_by_oid (crq, GNUTLS_OID_X520_COMMON_NAME, 0, "CN-Test", 7); if (ret < 0) { fail ("gnutls_x509_crq_set_dn_by_oid: %d\n", ret); } ret = gnutls_privkey_import_x509( abs_pkey, pkey, 0); if (ret < 0) { fail ("gnutls_privkey_import_x509: %d\n", ret); } ret = gnutls_x509_crq_privkey_sign (crq, abs_pkey, GNUTLS_DIG_SHA1, 0); if (ret < 0) { fail ("gnutls_x509_crq_sign: %d\n", ret); } ret = gnutls_x509_crq_verify (crq, 0); if (ret < 0) { fail ("gnutls_x509_crq_verify: %d\n", ret); } crq_key_id_len = 0; ret = gnutls_x509_crq_get_key_id (crq, 0, crq_key_id, &crq_key_id_len); if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { fail ("gnutls_x509_crq_get_key_id incorrectly returns %d\n", ret); } crq_key_id = malloc (sizeof (unsigned char) * crq_key_id_len); ret = gnutls_x509_crq_get_key_id (crq, 0, crq_key_id, &crq_key_id_len); if (ret != GNUTLS_E_SUCCESS) { fail ("gnutls_x509_crq_get_key_id incorrectly returns %d\n", ret); } if (crq_key_id_len == pkey_key_id_len) { ret = memcmp (crq_key_id, pkey_key_id, crq_key_id_len); if (ret == 0) { if (debug) success ("Key ids are identical. OK.\n"); } else { fail ("Key ids differ incorrectly: %d\n", ret); } } else { fail ("Key_id lengths differ incorrectly: %d - %d\n", (int) crq_key_id_len, (int) pkey_key_id_len); } if (pkey_key_id) { free (pkey_key_id); pkey_key_id = NULL; } if (crq_key_id) { free (crq_key_id); crq_key_id = NULL; } gnutls_x509_crq_deinit (crq); gnutls_x509_privkey_deinit (pkey); gnutls_privkey_deinit (abs_pkey); } gnutls_global_deinit (); }
bool load_p12(gnutls_certificate_credentials_t xcred, const char *const p12_file, const char *const password) { FILE*p12file; gnutls_datum_t p12blob; gnutls_pkcs12_t p12 = NULL; gnutls_x509_privkey_t key = NULL; gnutls_x509_crt_t certs[MAX_CERTS]; int certs_nr; int id_cert; uint8_t key_id[20]; size_t key_id_size; bool is_success = false; int ret; int i; assert(p12_file != NULL); /* Read file */ p12file = fopen(p12_file, "rb"); if(p12file == NULL) { trace(LOG_ERR, "failed to open PKCS#12 file '%s': %s (%d)", p12_file, strerror(errno), errno); ret = GNUTLS_E_FILE_ERROR; goto error; } p12blob.data = malloc(32768 * sizeof(char)); p12blob.size = fread((void*) p12blob.data, sizeof(char), 32768, p12file); fclose(p12file); /* Init structure and import P12 */ ret = gnutls_pkcs12_init(&p12); if(ret < 0) { trace(LOG_ERR, "failed to init PKCS#12 object (%d)", ret); goto free_blob; } ret = gnutls_pkcs12_import(p12, &p12blob, GNUTLS_X509_FMT_DER, 0); if(ret < 0) { trace(LOG_ERR, "failed to import PKCS#12 data (%d)", ret); goto deinit_pkcs12; } if(password) { ret = gnutls_pkcs12_verify_mac(p12, password); if(ret < 0) { trace(LOG_ERR, "failed to verify PKCS#12 MAC (%d)", ret); goto deinit_pkcs12; } } /* extract the private key and the certificates from PKCS#12 */ if(!tls_parse_pkcs12(&p12, password, &key, certs, &certs_nr)) { trace(LOG_ERR, "failed to parse PKCS#12 file '%s'", p12_file); goto deinit_pkcs12; } if(certs_nr < 2) { trace(LOG_ERR, "too few certificates in PKCS#12 file '%s'", p12_file); goto free_certs_key; } /* get the ID of private key */ key_id_size = sizeof(key_id); ret = gnutls_x509_privkey_get_key_id(key, 0, key_id, &key_id_size); if(ret < 0) { trace(LOG_ERR, "failed to get key ID"); goto free_certs_key; } id_cert = -1; for(i = 0; i < certs_nr; i++) { uint8_t cert_id[20]; size_t cert_id_size; cert_id_size = sizeof(cert_id); ret = gnutls_x509_crt_get_key_id(certs[i], 0, cert_id, &cert_id_size); if(ret < 0) { trace(LOG_ERR, "failed to get key ID for certificate #%d (%d)", i, ret); goto free_certs_key; } if(key_id_size == cert_id_size && memcmp(cert_id, key_id, cert_id_size) == 0) { /* it's the key certificate ! */ if(id_cert != -1) { ret = GNUTLS_E_INTERRUPTED; trace(LOG_ERR, "Duplicate key certificate !\n"); goto free_certs_key; } id_cert = i; } } if(id_cert == -1) { ret = GNUTLS_E_INTERRUPTED; trace(LOG_ERR, "Unable to find key certificate !\n"); goto free_certs_key; } /* Now have fun with the key and certs ! */ ret = gnutls_certificate_set_x509_key(xcred, &certs[id_cert], 1, key); if(ret < 0) { trace(LOG_ERR, "failed to set key for main certificate"); goto free_certs_key; } for(i = 0; i < certs_nr; i++) { if(i != id_cert) { ret = gnutls_certificate_set_x509_trust(xcred, &certs[i], 1); if(ret < 0) { trace(LOG_ERR, "failed to trust certificate #%d", i + 1); goto free_certs_key; } } } is_success = true; free_certs_key: gnutls_x509_privkey_deinit(key); for(i = 0; i < certs_nr; i++) { gnutls_x509_crt_deinit(certs[i]); } deinit_pkcs12: gnutls_pkcs12_deinit(p12); free_blob: free(p12blob.data); error: return is_success; }
static void privkey_info_int(FILE *outfile, common_info_st * cinfo, gnutls_x509_privkey_t key) { int ret, key_type; unsigned int bits = 0; size_t size; const char *cprint; /* Public key algorithm */ fprintf(outfile, "Public Key Info:\n"); ret = gnutls_x509_privkey_get_pk_algorithm2(key, &bits); fprintf(outfile, "\tPublic Key Algorithm: "); key_type = ret; cprint = gnutls_pk_algorithm_get_name(key_type); fprintf(outfile, "%s\n", cprint ? cprint : "Unknown"); fprintf(outfile, "\tKey Security Level: %s (%u bits)\n\n", gnutls_sec_param_get_name(gnutls_x509_privkey_sec_param (key)), bits); /* Print the raw public and private keys */ if (key_type == GNUTLS_PK_RSA) { gnutls_datum_t m, e, d, p, q, u, exp1, exp2; ret = gnutls_x509_privkey_export_rsa_raw2(key, &m, &e, &d, &p, &q, &u, &exp1, &exp2); if (ret < 0) fprintf(stderr, "Error in key RSA data export: %s\n", gnutls_strerror(ret)); else { print_rsa_pkey(outfile, &m, &e, &d, &p, &q, &u, &exp1, &exp2, cinfo->cprint); gnutls_free(m.data); gnutls_free(e.data); gnutls_free(d.data); gnutls_free(p.data); gnutls_free(q.data); gnutls_free(u.data); gnutls_free(exp1.data); gnutls_free(exp2.data); } } else if (key_type == GNUTLS_PK_DSA) { gnutls_datum_t p, q, g, y, x; ret = gnutls_x509_privkey_export_dsa_raw(key, &p, &q, &g, &y, &x); if (ret < 0) fprintf(stderr, "Error in key DSA data export: %s\n", gnutls_strerror(ret)); else { print_dsa_pkey(outfile, &x, &y, &p, &q, &g, cinfo->cprint); gnutls_free(x.data); gnutls_free(y.data); gnutls_free(p.data); gnutls_free(q.data); gnutls_free(g.data); } } else if (key_type == GNUTLS_PK_EC) { gnutls_datum_t y, x, k; gnutls_ecc_curve_t curve; ret = gnutls_x509_privkey_export_ecc_raw(key, &curve, &x, &y, &k); if (ret < 0) fprintf(stderr, "Error in key ECC data export: %s\n", gnutls_strerror(ret)); else { cprint = gnutls_ecc_curve_get_name(curve); bits = 0; print_ecc_pkey(outfile, curve, &k, &x, &y, cinfo->cprint); gnutls_free(x.data); gnutls_free(y.data); gnutls_free(k.data); } } fprintf(outfile, "\n"); size = lbuffer_size; ret = gnutls_x509_privkey_get_seed(key, NULL, lbuffer, &size); if (ret >= 0) { fprintf(outfile, "Seed: %s\n", raw_to_string(lbuffer, size)); } size = lbuffer_size; ret = gnutls_x509_privkey_get_key_id(key, GNUTLS_KEYID_USE_SHA256, lbuffer, &size); if (ret < 0) { fprintf(stderr, "Error in key id calculation: %s\n", gnutls_strerror(ret)); } else { gnutls_datum_t art; fprintf(outfile, "Public Key ID:\n\tsha256:%s\n", raw_to_string(lbuffer, size)); size = lbuffer_size; ret = gnutls_x509_privkey_get_key_id(key, GNUTLS_KEYID_USE_SHA1, lbuffer, &size); if (ret >= 0) { fprintf(outfile, "\tsha1:%s\n", raw_to_string(lbuffer, size)); } ret = gnutls_random_art(GNUTLS_RANDOM_ART_OPENSSH, cprint, bits, lbuffer, size, &art); if (ret >= 0) { fprintf(outfile, "Public key's random art:\n%s\n", art.data); gnutls_free(art.data); } } fprintf(outfile, "\n"); }