/* A generic export function. Will export the given ASN.1 encoded data * to PEM or DER raw data. */ int _gnutls_x509_export_int_named2(ASN1_TYPE asn1_data, const char *name, gnutls_x509_crt_fmt_t format, const char *pem_header, gnutls_datum_t * out) { int ret; if (format == GNUTLS_X509_FMT_DER) { ret = _gnutls_x509_der_encode(asn1_data, name, out, 0); if (ret < 0) return gnutls_assert_val(ret); } else { /* PEM */ gnutls_datum_t tmp; ret = _gnutls_x509_der_encode(asn1_data, name, &tmp, 0); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_fbase64_encode(pem_header, tmp.data, tmp.size, out); _gnutls_free_datum(&tmp); if (ret < 0) return gnutls_assert_val(ret); } return 0; }
/** * gnutls_pem_base64_encode: * @msg: is a message to be put in the header * @data: contain the raw data * @result: the place where base64 data will be copied * @result_size: holds the size of the result * * This function will convert the given data to printable data, using * the base64 encoding. This is the encoding used in PEM messages. * * The output string will be null terminated, although the size will * not include the terminating null. * * Returns: On success %GNUTLS_E_SUCCESS (0) is returned, * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is * not long enough, or 0 on success. **/ int gnutls_pem_base64_encode (const char *msg, const gnutls_datum_t * data, char *result, size_t * result_size) { gnutls_datum_t res; int ret; ret = _gnutls_fbase64_encode (msg, data->data, data->size, &res); if (ret < 0) return ret; if (result == NULL || *result_size < (unsigned) res.size) { gnutls_free (res.data); *result_size = res.size + 1; return GNUTLS_E_SHORT_MEMORY_BUFFER; } else { memcpy (result, res.data, res.size); gnutls_free (res.data); *result_size = res.size; } return 0; }
/** * gnutls_pem_base64_encode_alloc: * @msg: is a message to be put in the encoded header * @data: contains the raw data * @result: will hold the newly allocated encoded data * * This function will convert the given data to printable data, using * the base64 encoding. This is the encoding used in PEM messages. * This function will allocate the required memory to hold the encoded * data. * * You should use gnutls_free() to free the returned data. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise * an error code is returned. **/ int gnutls_pem_base64_encode_alloc (const char *msg, const gnutls_datum_t * data, gnutls_datum_t * result) { int ret; if (result == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ret = _gnutls_fbase64_encode (msg, data->data, data->size, result); if (ret < 0) return gnutls_assert_val(ret); return 0; }
/** * gnutls_dh_params_export_pkcs3 - export DH params to a pkcs3 structure * @params: Holds the DH parameters * @format: the format of output params. One of PEM or DER. * @params_data: will contain a PKCS3 DHParams structure PEM or DER encoded * @params_data_size: holds the size of params_data (and will be replaced by the actual size of parameters) * * This function will export the given dh parameters to a PKCS3 * DHParams structure. This is the format generated by "openssl dhparam" tool. * If the buffer provided is not long enough to hold the output, then * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned. * * If the structure is PEM encoded, it will have a header * of "BEGIN DH PARAMETERS". * * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned, * otherwise an error code is returned. **/ int gnutls_dh_params_export_pkcs3 (gnutls_dh_params_t params, gnutls_x509_crt_fmt_t format, unsigned char *params_data, size_t * params_data_size) { ASN1_TYPE c2; int result, _params_data_size; size_t g_size, p_size; opaque *p_data, *g_data; opaque *all_data; _gnutls_mpi_print_lz (params->params[1], NULL, &g_size); _gnutls_mpi_print_lz (params->params[0], NULL, &p_size); all_data = gnutls_malloc (g_size + p_size); if (all_data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } p_data = &all_data[0]; g_data = &all_data[p_size]; _gnutls_mpi_print_lz (params->params[0], p_data, &p_size); _gnutls_mpi_print_lz (params->params[1], g_data, &g_size); /* Ok. Now we have the data. Create the asn1 structures */ if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), "GNUTLS.DHParameter", &c2)) != ASN1_SUCCESS) { gnutls_assert (); gnutls_free (all_data); return _gnutls_asn2err (result); } /* Write PRIME */ if ((result = asn1_write_value (c2, "prime", p_data, p_size)) != ASN1_SUCCESS) { gnutls_assert (); gnutls_free (all_data); asn1_delete_structure (&c2); return _gnutls_asn2err (result); } /* Write the GENERATOR */ if ((result = asn1_write_value (c2, "base", g_data, g_size)) != ASN1_SUCCESS) { gnutls_assert (); gnutls_free (all_data); asn1_delete_structure (&c2); return _gnutls_asn2err (result); } gnutls_free (all_data); if ((result = asn1_write_value (c2, "privateValueLength", NULL, 0)) != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&c2); return _gnutls_asn2err (result); } if (format == GNUTLS_X509_FMT_DER) { if (params_data == NULL) *params_data_size = 0; _params_data_size = *params_data_size; result = asn1_der_coding (c2, "", params_data, &_params_data_size, NULL); *params_data_size = _params_data_size; asn1_delete_structure (&c2); if (result != ASN1_SUCCESS) { gnutls_assert (); if (result == ASN1_MEM_ERROR) return GNUTLS_E_SHORT_MEMORY_BUFFER; return _gnutls_asn2err (result); } } else { /* PEM */ opaque *tmp; opaque *out; int len; len = 0; asn1_der_coding (c2, "", NULL, &len, NULL); tmp = gnutls_malloc (len); if (tmp == NULL) { gnutls_assert (); asn1_delete_structure (&c2); return GNUTLS_E_MEMORY_ERROR; } if ((result = asn1_der_coding (c2, "", tmp, &len, NULL)) != ASN1_SUCCESS) { gnutls_assert (); gnutls_free (tmp); asn1_delete_structure (&c2); return _gnutls_asn2err (result); } asn1_delete_structure (&c2); result = _gnutls_fbase64_encode ("DH PARAMETERS", tmp, len, &out); gnutls_free (tmp); if (result < 0) { gnutls_assert (); return result; } if (result == 0) { /* oooops */ gnutls_assert (); gnutls_free (out); return GNUTLS_E_INTERNAL_ERROR; } if ((unsigned) result > *params_data_size) { gnutls_assert (); gnutls_free (out); *params_data_size = result; return GNUTLS_E_SHORT_MEMORY_BUFFER; } *params_data_size = result - 1; if (params_data) memcpy (params_data, out, result); gnutls_free (out); } return 0; }
/* A generic export function. Will export the given ASN.1 encoded data * to PEM or DER raw data. */ int _gnutls_x509_export_int_named (ASN1_TYPE asn1_data, const char *name, gnutls_x509_crt_fmt_t format, const char *pem_header, unsigned char *output_data, size_t * output_data_size) { int result, len; if (format == GNUTLS_X509_FMT_DER) { if (output_data == NULL) *output_data_size = 0; len = *output_data_size; if ((result = asn1_der_coding (asn1_data, name, output_data, &len, NULL)) != ASN1_SUCCESS) { *output_data_size = len; if (result == ASN1_MEM_ERROR) { return GNUTLS_E_SHORT_MEMORY_BUFFER; } gnutls_assert (); return _gnutls_asn2err (result); } *output_data_size = len; } else { /* PEM */ opaque *out; gnutls_datum_t tmp; result = _gnutls_x509_der_encode (asn1_data, name, &tmp, 0); if (result < 0) { gnutls_assert (); return result; } result = _gnutls_fbase64_encode (pem_header, tmp.data, tmp.size, &out); _gnutls_free_datum (&tmp); if (result < 0) { gnutls_assert (); return result; } if (result == 0) { /* oooops */ gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } if ((unsigned) result > *output_data_size) { gnutls_assert (); gnutls_free (out); *output_data_size = result; return GNUTLS_E_SHORT_MEMORY_BUFFER; } *output_data_size = result; if (output_data) { memcpy (output_data, out, result); /* do not include the null character into output size. */ *output_data_size = result - 1; } gnutls_free (out); } return 0; }
/** * gnutls_dh_params_export2_pkcs3: * @params: Holds the DH parameters * @format: the format of output params. One of PEM or DER. * @out: will contain a PKCS3 DHParams structure PEM or DER encoded * * This function will export the given dh parameters to a PKCS3 * DHParams structure. This is the format generated by "openssl dhparam" tool. * The data in @out will be allocated using gnutls_malloc(). * * If the structure is PEM encoded, it will have a header * of "BEGIN DH PARAMETERS". * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, * otherwise a negative error code is returned. * * Since: 3.1.3 **/ int gnutls_dh_params_export2_pkcs3(gnutls_dh_params_t params, gnutls_x509_crt_fmt_t format, gnutls_datum_t * out) { ASN1_TYPE c2; int result; size_t g_size, p_size; uint8_t *p_data, *g_data; uint8_t *all_data; _gnutls_mpi_print_lz(params->params[1], NULL, &g_size); _gnutls_mpi_print_lz(params->params[0], NULL, &p_size); all_data = gnutls_malloc(g_size + p_size); if (all_data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } p_data = &all_data[0]; _gnutls_mpi_print_lz(params->params[0], p_data, &p_size); g_data = &all_data[p_size]; _gnutls_mpi_print_lz(params->params[1], g_data, &g_size); /* Ok. Now we have the data. Create the asn1 structures */ if ((result = asn1_create_element (_gnutls_get_gnutls_asn(), "GNUTLS.DHParameter", &c2)) != ASN1_SUCCESS) { gnutls_assert(); gnutls_free(all_data); return _gnutls_asn2err(result); } /* Write PRIME */ if ((result = asn1_write_value(c2, "prime", p_data, p_size)) != ASN1_SUCCESS) { gnutls_assert(); gnutls_free(all_data); asn1_delete_structure(&c2); return _gnutls_asn2err(result); } if (params->q_bits > 0) result = _gnutls_x509_write_uint32(c2, "privateValueLength", params->q_bits); else result = asn1_write_value(c2, "privateValueLength", NULL, 0); if (result < 0) { gnutls_assert(); gnutls_free(all_data); asn1_delete_structure(&c2); return _gnutls_asn2err(result); } /* Write the GENERATOR */ if ((result = asn1_write_value(c2, "base", g_data, g_size)) != ASN1_SUCCESS) { gnutls_assert(); gnutls_free(all_data); asn1_delete_structure(&c2); return _gnutls_asn2err(result); } gnutls_free(all_data); if (format == GNUTLS_X509_FMT_DER) { result = _gnutls_x509_der_encode(c2, "", out, 0); asn1_delete_structure(&c2); if (result < 0) return gnutls_assert_val(result); } else { /* PEM */ gnutls_datum_t t; result = _gnutls_x509_der_encode(c2, "", &t, 0); asn1_delete_structure(&c2); if (result < 0) return gnutls_assert_val(result); result = _gnutls_fbase64_encode("DH PARAMETERS", t.data, t.size, out); gnutls_free(t.data); if (result < 0) { gnutls_assert(); return result; } } return 0; }
/** * gnutls_tpm_privkey_generate: * @pk: the public key algorithm * @bits: the security bits * @srk_password: a password to protect the exported key (optional) * @key_password: the password for the TPM (optional) * @format: the format of the private key * @pub_format: the format of the public key * @privkey: the generated key * @pubkey: the corresponding public key (may be null) * @flags: should be a list of GNUTLS_TPM_* flags * * This function will generate a private key in the TPM * chip. The private key will be generated within the chip * and will be exported in a wrapped with TPM's master key * form. Furthermore the wrapped key can be protected with * the provided @password. * * Note that bits in TPM is quantized value. If the input value * is not one of the allowed values, then it will be quantized to * one of 512, 1024, 2048, 4096, 8192 and 16384. * * Allowed flags are: * * %GNUTLS_TPM_KEY_SIGNING: Generate a signing key instead of a legacy, * %GNUTLS_TPM_REGISTER_KEY: Register the generate key in TPM. In that * case @privkey would contain a URL with the UUID. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1.0 **/ int gnutls_tpm_privkey_generate(gnutls_pk_algorithm_t pk, unsigned int bits, const char *srk_password, const char *key_password, gnutls_tpmkey_fmt_t format, gnutls_x509_crt_fmt_t pub_format, gnutls_datum_t * privkey, gnutls_datum_t * pubkey, unsigned int flags) { TSS_FLAG tpm_flags = TSS_KEY_VOLATILE; TSS_HKEY key_ctx; TSS_RESULT tssret; int ret; void *tdata; UINT32 tint; gnutls_datum_t tmpkey = { NULL, 0 }; TSS_HPOLICY key_policy; gnutls_pubkey_t pub; struct tpm_ctx_st s; TSS_FLAG storage_type; TSS_HTPM htpm; uint8_t buf[32]; if (flags & GNUTLS_TPM_KEY_SIGNING) tpm_flags |= TSS_KEY_TYPE_SIGNING; else tpm_flags |= TSS_KEY_TYPE_LEGACY; if (flags & GNUTLS_TPM_KEY_USER) storage_type = TSS_PS_TYPE_USER; else storage_type = TSS_PS_TYPE_SYSTEM; if (bits <= 512) tpm_flags |= TSS_KEY_SIZE_512; else if (bits <= 1024) tpm_flags |= TSS_KEY_SIZE_1024; else if (bits <= 2048) tpm_flags |= TSS_KEY_SIZE_2048; else if (bits <= 4096) tpm_flags |= TSS_KEY_SIZE_4096; else if (bits <= 8192) tpm_flags |= TSS_KEY_SIZE_8192; else tpm_flags |= TSS_KEY_SIZE_16384; ret = tpm_open_session(&s, srk_password); if (ret < 0) return gnutls_assert_val(ret); /* put some randomness into TPM. * Let's not trust it completely. */ tssret = Tspi_Context_GetTpmObject(s.tpm_ctx, &htpm); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_cc; } ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buf, sizeof(buf)); if (ret < 0) { gnutls_assert(); goto err_cc; } tssret = Tspi_TPM_StirRandom(htpm, sizeof(buf), buf); if (tssret) { gnutls_assert(); } tssret = Tspi_Context_CreateObject(s.tpm_ctx, TSS_OBJECT_TYPE_RSAKEY, tpm_flags, &key_ctx); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_cc; } tssret = Tspi_SetAttribUint32(key_ctx, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIGSCHEME, TSS_SS_RSASSAPKCS1V15_DER); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } /* set the password of the actual key */ if (key_password) { tssret = Tspi_GetPolicyObject(key_ctx, TSS_POLICY_USAGE, &key_policy); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } tssret = myTspi_Policy_SetSecret(key_policy, SAFE_LEN(key_password), (void *) key_password); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } } tssret = Tspi_Key_CreateKey(key_ctx, s.srk, 0); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } if (flags & GNUTLS_TPM_REGISTER_KEY) { TSS_UUID key_uuid; ret = randomize_uuid(&key_uuid); if (ret < 0) { gnutls_assert(); goto err_sa; } tssret = Tspi_Context_RegisterKey(s.tpm_ctx, key_ctx, storage_type, key_uuid, TSS_PS_TYPE_SYSTEM, srk_uuid); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } ret = encode_tpmkey_url((char **) &privkey->data, &key_uuid, storage_type); if (ret < 0) { TSS_HKEY tkey; Tspi_Context_UnregisterKey(s.tpm_ctx, storage_type, key_uuid, &tkey); gnutls_assert(); goto err_sa; } privkey->size = strlen((char *) privkey->data); } else { /* get the key as blob */ tssret = Tspi_GetAttribData(key_ctx, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, &tint, (void *) &tdata); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } if (format == GNUTLS_TPMKEY_FMT_CTK_PEM) { ret = _gnutls_x509_encode_string (ASN1_ETYPE_OCTET_STRING, tdata, tint, &tmpkey); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_fbase64_encode("TSS KEY BLOB", tmpkey.data, tmpkey.size, privkey); if (ret < 0) { gnutls_assert(); goto cleanup; } } else { UINT32 tint2; tmpkey.size = tint + 32; /* spec says no more than 20 */ tmpkey.data = gnutls_malloc(tmpkey.size); if (tmpkey.data == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } tint2 = tmpkey.size; tssret = Tspi_EncodeDER_TssBlob(tint, tdata, TSS_BLOB_TYPE_PRIVATEKEY, &tint2, tmpkey.data); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto cleanup; } tmpkey.size = tint2; privkey->data = tmpkey.data; privkey->size = tmpkey.size; tmpkey.data = NULL; } } /* read the public key */ if (pubkey != NULL) { size_t psize; ret = gnutls_pubkey_init(&pub); if (ret < 0) { gnutls_assert(); goto privkey_cleanup; } ret = read_pubkey(pub, key_ctx, &psize); if (ret < 0) { gnutls_assert(); goto privkey_cleanup; } psize += 512; pubkey->data = gnutls_malloc(psize); if (pubkey->data == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto pubkey_cleanup; } ret = gnutls_pubkey_export(pub, pub_format, pubkey->data, &psize); if (ret < 0) { gnutls_assert(); goto pubkey_cleanup; } pubkey->size = psize; gnutls_pubkey_deinit(pub); } ret = 0; goto cleanup; pubkey_cleanup: gnutls_pubkey_deinit(pub); privkey_cleanup: gnutls_free(privkey->data); privkey->data = NULL; cleanup: gnutls_free(tmpkey.data); tmpkey.data = NULL; err_sa: Tspi_Context_CloseObject(s.tpm_ctx, key_ctx); err_cc: tpm_close_session(&s); return ret; }
/* A generic export function. Will export the given ASN.1 encoded data * to PEM or DER raw data. */ int _gnutls_x509_export_int (ASN1_TYPE asn1_data, gnutls_x509_crt_fmt_t format, char *pem_header, int tmp_buf_size, unsigned char *output_data, size_t * output_data_size) { int result, len; if (tmp_buf_size == 0) tmp_buf_size = 16 * 1024; if (format == GNUTLS_X509_FMT_DER) { if (output_data == NULL) *output_data_size = 0; len = *output_data_size; if ((result = asn1_der_coding (asn1_data, "", output_data, &len, NULL)) != ASN1_SUCCESS) { *output_data_size = len; if (result == ASN1_MEM_ERROR) { return GNUTLS_E_SHORT_MEMORY_BUFFER; } gnutls_assert (); return _gnutls_asn2err (result); } *output_data_size = len; } else { /* PEM */ opaque *tmp; opaque *out; len = tmp_buf_size; tmp = gnutls_alloca (len); if (tmp == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } if ((result = asn1_der_coding (asn1_data, "", tmp, &len, NULL)) != ASN1_SUCCESS) { gnutls_assert (); if (result == ASN1_MEM_ERROR) { *output_data_size = B64FSIZE (strlen (pem_header), len) + 1; } gnutls_afree (tmp); return _gnutls_asn2err (result); } result = _gnutls_fbase64_encode (pem_header, tmp, len, &out); gnutls_afree (tmp); if (result < 0) { gnutls_assert (); return result; } if (result == 0) { /* oooops */ gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } if ((unsigned) result > *output_data_size) { gnutls_assert (); gnutls_free (out); *output_data_size = result; return GNUTLS_E_SHORT_MEMORY_BUFFER; } *output_data_size = result; if (output_data) { memcpy (output_data, out, result); /* do not include the null character into output size. */ *output_data_size = result - 1; } gnutls_free (out); } return 0; }