gboolean li_gnutls_ocsp_search_datum(liServer *srv, liGnuTLSOCSP *ocsp, gnutls_datum_t const* file) { int r; gnutls_datum_t decoded = { NULL, 0 }; gboolean result = FALSE; r = gnutls_pem_base64_decode_alloc("OCSP RESPONSE", file, &decoded); if (GNUTLS_E_SUCCESS <= r) { result = add_response(srv, ocsp, &decoded); if (!result) { ERROR(srv, "%s", "Failed loading OCSP response from PEM block"); goto error; } } else if (GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR == r) { /* ignore GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR */ } else { ERROR(srv, "gnutls_pem_base64_decode_alloc failed to decode OCSP RESPONSE from PEM block (%s): %s", gnutls_strerror_name(r), gnutls_strerror(r)); /* continue anyway */ } result = TRUE; error: gnutls_free(decoded.data); return result; }
/* this bit is based on read_ca_file() in gnutls */ static int tls_compare_certificates (const gnutls_datum *peercert) { gnutls_datum cert; unsigned char *ptr; FILE *fd1; int ret; gnutls_datum b64_data; unsigned char *b64_data_data; struct stat filestat; if (stat(SslCertFile, &filestat) == -1) return 0; b64_data.size = filestat.st_size+1; b64_data_data = (unsigned char *) safe_calloc (1, b64_data.size); b64_data_data[b64_data.size-1] = '\0'; b64_data.data = b64_data_data; fd1 = fopen(SslCertFile, "r"); if (fd1 == NULL) { return 0; } b64_data.size = fread(b64_data.data, 1, b64_data.size, fd1); fclose(fd1); do { ret = gnutls_pem_base64_decode_alloc(NULL, &b64_data, &cert); if (ret != 0) { FREE (&b64_data_data); return 0; } ptr = (unsigned char *)strstr((char*)b64_data.data, CERT_SEP) + 1; ptr = (unsigned char *)strstr((char*)ptr, CERT_SEP); b64_data.size = b64_data.size - (ptr - b64_data.data); b64_data.data = ptr; if (cert.size == peercert->size) { if (memcmp (cert.data, peercert->data, cert.size) == 0) { /* match found */ gnutls_free(cert.data); FREE (&b64_data_data); return 1; } } gnutls_free(cert.data); } while (ptr != NULL); /* no match found */ FREE (&b64_data_data); return 0; }
gboolean li_gnutls_ocsp_add(liServer *srv, liGnuTLSOCSP *ocsp, const char* filename) { int r; gnutls_datum_t file = { NULL, 0 }; gnutls_datum_t decoded = { NULL, 0 }; gnutls_datum_t* der_data; gboolean result = FALSE; if (GNUTLS_E_SUCCESS > (r = gnutls_load_file(filename, &file))) { ERROR(srv, "Failed to load OCSP file '%s' (%s): %s", filename, gnutls_strerror_name(r), gnutls_strerror(r)); goto error; } /* decode pem "-----BEGIN OCSP RESPONSE-----", otherwise expect DER */ if (file.size > 20 && 0 == memcmp(file.data, CONST_STR_LEN("-----BEGIN "))) { r = gnutls_pem_base64_decode_alloc("OCSP RESPONSE", &file, &decoded); if (GNUTLS_E_SUCCESS > r) { ERROR(srv, "gnutls_pem_base64_decode_alloc failed to decode OCSP RESPONSE from '%s' (%s): %s", filename, gnutls_strerror_name(r), gnutls_strerror(r)); goto error; } der_data = &decoded; } else { der_data = &file; } result = add_response(srv, ocsp, der_data); if (!result) { ERROR(srv, "Failed loading OCSP response from '%s'", filename); } error: gnutls_free(file.data); gnutls_free(decoded.data); return result; }
int load_tpm_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata, gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig) { static const TSS_UUID SRK_UUID = TSS_UUID_SRK; gnutls_datum_t asn1; unsigned int tss_len; char *pass; int ofs, err; err = gnutls_pem_base64_decode_alloc("TSS KEY BLOB", fdata, &asn1); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Error decoding TSS key blob: %s\n"), gnutls_strerror(err)); return -EINVAL; } /* Ick. We have to parse the ASN1 OCTET_STRING for ourselves. */ if (asn1.size < 2 || asn1.data[0] != 0x04 /* OCTET_STRING */) { vpn_progress(vpninfo, PRG_ERR, _("Error in TSS key blob\n")); goto out_blob; } tss_len = asn1.data[1]; ofs = 2; if (tss_len & 0x80) { int lenlen = tss_len & 0x7f; if (asn1.size < 2 + lenlen || lenlen > 3) { vpn_progress(vpninfo, PRG_ERR, _("Error in TSS key blob\n")); goto out_blob; } tss_len = 0; while (lenlen) { tss_len <<= 8; tss_len |= asn1.data[ofs++]; lenlen--; } } if (tss_len + ofs != asn1.size) { vpn_progress(vpninfo, PRG_ERR, _("Error in TSS key blob\n")); goto out_blob; } err = Tspi_Context_Create(&vpninfo->tpm_context); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to create TPM context: %s\n"), Trspi_Error_String(err)); goto out_blob; } err = Tspi_Context_Connect(vpninfo->tpm_context, NULL); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to connect TPM context: %s\n"), Trspi_Error_String(err)); goto out_context; } err = Tspi_Context_LoadKeyByUUID(vpninfo->tpm_context, TSS_PS_TYPE_SYSTEM, SRK_UUID, &vpninfo->srk); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to load TPM SRK key: %s\n"), Trspi_Error_String(err)); goto out_context; } err = Tspi_GetPolicyObject(vpninfo->srk, TSS_POLICY_USAGE, &vpninfo->srk_policy); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to load TPM SRK policy object: %s\n"), Trspi_Error_String(err)); goto out_srk; } pass = vpninfo->cert_password; vpninfo->cert_password = NULL; while (1) { static const char nullpass[20]; /* We don't seem to get the error here... */ if (pass) err = Tspi_Policy_SetSecret(vpninfo->srk_policy, TSS_SECRET_MODE_PLAIN, strlen(pass), (BYTE *)pass); else /* Well-known NULL key */ err = Tspi_Policy_SetSecret(vpninfo->srk_policy, TSS_SECRET_MODE_SHA1, sizeof(nullpass), (BYTE *)nullpass); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to set TPM PIN: %s\n"), Trspi_Error_String(err)); goto out_srkpol; } free(pass); /* ... we get it here instead. */ err = Tspi_Context_LoadKeyByBlob(vpninfo->tpm_context, vpninfo->srk, tss_len, asn1.data + ofs, &vpninfo->tpm_key); if (!err) break; if (pass) vpn_progress(vpninfo, PRG_ERR, _("Failed to load TPM key blob: %s\n"), Trspi_Error_String(err)); if (err != TPM_E_AUTHFAIL) goto out_srkpol; err = request_passphrase(vpninfo, "openconnect_tpm_srk", &pass, _("Enter TPM SRK PIN:")); if (err) goto out_srkpol; } #ifdef HAVE_GNUTLS_CERTIFICATE_SET_KEY gnutls_privkey_init(pkey); /* This would be nicer if there was a destructor callback. I could allocate a data structure with the TPM handles and the vpninfo pointer, and destroy that properly when the key is destroyed. */ gnutls_privkey_import_ext(*pkey, GNUTLS_PK_RSA, vpninfo, tpm_sign_fn, NULL, 0); #else *pkey = OPENCONNECT_TPM_PKEY; #endif retry_sign: err = sign_dummy_data(vpninfo, *pkey, fdata, pkey_sig); if (err == GNUTLS_E_INSUFFICIENT_CREDENTIALS) { if (!vpninfo->tpm_key_policy) { err = Tspi_Context_CreateObject(vpninfo->tpm_context, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &vpninfo->tpm_key_policy); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to create key policy object: %s\n"), Trspi_Error_String(err)); goto out_key; } err = Tspi_Policy_AssignToObject(vpninfo->tpm_key_policy, vpninfo->tpm_key); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to assign policy to key: %s\n"), Trspi_Error_String(err)); goto out_key_policy; } } err = request_passphrase(vpninfo, "openconnect_tpm_key", &pass, _("Enter TPM key PIN:")); if (err) goto out_key_policy; err = Tspi_Policy_SetSecret(vpninfo->tpm_key_policy, TSS_SECRET_MODE_PLAIN, strlen(pass), (void *)pass); free (pass); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to set key PIN: %s\n"), Trspi_Error_String(err)); goto out_key_policy; } goto retry_sign; } free (asn1.data); return 0; out_key_policy: Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->tpm_key_policy); vpninfo->tpm_key_policy = 0; out_key: Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->tpm_key); vpninfo->tpm_key = 0; out_srkpol: Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->srk_policy); vpninfo->srk_policy = 0; out_srk: Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->srk); vpninfo->srk = 0; out_context: Tspi_Context_Close(vpninfo->tpm_context); vpninfo->tpm_context = 0; out_blob: free (asn1.data); return -EIO; }
void doit(void) { gnutls_datum_t der_cert, der_cert2; int ret; gnutls_datum_t hash; /* the sha1 hash of the server's pubkey */ hash.data = (void *) SHA1_HASH; hash.size = sizeof(SHA1_HASH) - 1; /* General init. */ global_init(); gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(2); ret = gnutls_pem_base64_decode_alloc("CERTIFICATE", &server_cert, &der_cert); if (ret < 0) { fail("base64 decoding\n"); goto fail; } ret = gnutls_pem_base64_decode_alloc("CERTIFICATE", &client_cert, &der_cert2); if (ret < 0) { fail("base64 decoding\n"); goto fail; } remove(TMP_FILE); /* verify whether the stored hash verification succeeeds */ ret = gnutls_store_commitment(TMP_FILE, NULL, "localhost", "https", GNUTLS_DIG_SHA1, &hash, 0, 0); if (ret != 0) { fail("commitment storage: %s\n", gnutls_strerror(ret)); goto fail; } if (debug) success("Commitment storage: passed\n"); ret = gnutls_verify_stored_pubkey(TMP_FILE, NULL, "localhost", "https", GNUTLS_CRT_X509, &der_cert, 0); remove(TMP_FILE); if (ret != 0) { fail("commitment verification: %s\n", gnutls_strerror(ret)); goto fail; } if (debug) success("Commitment verification: passed\n"); /* verify whether the stored pubkey verification succeeeds */ ret = gnutls_store_pubkey(TMP_FILE, NULL, "localhost", "https", GNUTLS_CRT_X509, &der_cert, 0, 0); if (ret != 0) { fail("storage: %s\n", gnutls_strerror(ret)); goto fail; } if (debug) success("Public key storage: passed\n"); ret = gnutls_verify_stored_pubkey(TMP_FILE, NULL, "localhost", "https", GNUTLS_CRT_X509, &der_cert, 0); if (ret != 0) { fail("pubkey verification: %s\n", gnutls_strerror(ret)); goto fail; } ret = gnutls_verify_stored_pubkey(TMP_FILE, NULL, "localhost", "https", GNUTLS_CRT_X509, &der_cert2, 0); remove(TMP_FILE); if (ret == 0) { fail("verification succeed when shouldn't!\n"); goto fail; } if (ret != GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { fail("Wrong error code returned: %s!\n", gnutls_strerror(ret)); goto fail; } if (debug) success("Public key verification: passed\n"); gnutls_global_deinit(); gnutls_free(der_cert.data); gnutls_free(der_cert2.data); return; fail: remove(TMP_FILE); exit(1); }
static int load_key(TSS_HCONTEXT tpm_ctx, TSS_HKEY srk, const gnutls_datum_t * fdata, gnutls_tpmkey_fmt_t format, TSS_HKEY * tpm_key) { int ret, err; gnutls_datum_t asn1 = { NULL, 0 }; if (format == GNUTLS_TPMKEY_FMT_CTK_PEM) { gnutls_datum_t td; ret = gnutls_pem_base64_decode_alloc("TSS KEY BLOB", fdata, &asn1); if (ret) { gnutls_assert(); _gnutls_debug_log ("Error decoding TSS key blob: %s\n", gnutls_strerror(ret)); return ret; } ret = _gnutls_x509_decode_string(ASN1_ETYPE_OCTET_STRING, asn1.data, asn1.size, &td); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_free(asn1.data); asn1.data = td.data; asn1.size = td.size; } else { /* DER */ UINT32 tint2; UINT32 type; asn1.size = fdata->size; asn1.data = gnutls_malloc(asn1.size); if (asn1.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } tint2 = asn1.size; err = Tspi_DecodeBER_TssBlob(fdata->size, fdata->data, &type, &tint2, asn1.data); if (err != 0) { gnutls_assert(); ret = tss_err(err); goto cleanup; } asn1.size = tint2; } /* ... we get it here instead. */ err = Tspi_Context_LoadKeyByBlob(tpm_ctx, srk, asn1.size, asn1.data, tpm_key); if (err != 0) { gnutls_assert(); ret = tss_err(err); goto cleanup; } ret = 0; cleanup: gnutls_free(asn1.data); return ret; }
/** * tls_compare_certificates - Compare certificates against #C_CertificateFile * @param peercert Certificate * @retval 1 Certificate matches file * @retval 0 Error, or no match */ static int tls_compare_certificates(const gnutls_datum_t *peercert) { gnutls_datum_t cert; unsigned char *ptr = NULL; gnutls_datum_t b64_data; unsigned char *b64_data_data = NULL; struct stat filestat; if (stat(C_CertificateFile, &filestat) == -1) return 0; b64_data.size = filestat.st_size + 1; b64_data_data = mutt_mem_calloc(1, b64_data.size); b64_data_data[b64_data.size - 1] = '\0'; b64_data.data = b64_data_data; FILE *fp = fopen(C_CertificateFile, "r"); if (!fp) return 0; b64_data.size = fread(b64_data.data, 1, b64_data.size, fp); mutt_file_fclose(&fp); do { const int ret = gnutls_pem_base64_decode_alloc(NULL, &b64_data, &cert); if (ret != 0) { FREE(&b64_data_data); return 0; } /* find start of cert, skipping junk */ ptr = (unsigned char *) strstr((char *) b64_data.data, CERT_SEP); if (!ptr) { gnutls_free(cert.data); FREE(&b64_data_data); return 0; } /* find start of next cert */ ptr = (unsigned char *) strstr((char *) ptr + 1, CERT_SEP); b64_data.size = b64_data.size - (ptr - b64_data.data); b64_data.data = ptr; if (cert.size == peercert->size) { if (memcmp(cert.data, peercert->data, cert.size) == 0) { /* match found */ gnutls_free(cert.data); FREE(&b64_data_data); return 1; } } gnutls_free(cert.data); } while (ptr); /* no match found */ FREE(&b64_data_data); return 0; }