static int cert_verify_callback (gnutls_session_t session) { int rc; unsigned int status = 0; int ssh = ENABLED_OPT(TOFU); const char* txt_service; if (!x509_cafile && !pgp_keyring) return 0; rc = cert_verify(session, hostname); if (rc == 0) { printf ("*** Verifying server certificate failed...\n"); if (!insecure && !ssh) return -1; } else if (ENABLED_OPT(OCSP)) { /* off-line verification succeeded. Try OCSP */ rc = cert_verify_ocsp(session); if (rc == 0) { printf ("*** Verifying (with OCSP) server certificate failed...\n"); if (!insecure && !ssh) return -1; } else if (rc == -1) printf("*** OCSP response ignored\n"); } if (ssh) /* try ssh auth */ { unsigned int list_size; const gnutls_datum_t * cert; cert = gnutls_certificate_get_peers(session, &list_size); if (cert == NULL) { fprintf(stderr, "Cannot obtain peer's certificate!\n"); return -1; } txt_service = port_to_service(service); rc = gnutls_verify_stored_pubkey(NULL, NULL, hostname, txt_service, GNUTLS_CRT_X509, cert, 0); if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND) { print_cert_info_compact(session); fprintf(stderr, "Host %s (%s) has never been contacted before.\n", hostname, txt_service); if (status == 0) fprintf(stderr, "Its certificate is valid for %s.\n", hostname); rc = read_yesno("Are you sure you want to trust it? (y/N): "); if (rc == 0) return -1; } else if (rc == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { print_cert_info_compact(session); fprintf(stderr, "Warning: host %s is known and it is associated with a different key.\n", hostname); fprintf(stderr, "It might be that the server has multiple keys, or an attacker replaced the key to eavesdrop this connection .\n"); if (status == 0) fprintf(stderr, "Its certificate is valid for %s.\n", hostname); rc = read_yesno("Do you trust the received key? (y/N): "); if (rc == 0) return -1; } else if (rc < 0) { fprintf(stderr, "gnutls_verify_stored_pubkey: %s\n", gnutls_strerror(rc)); return -1; } if (rc != 0) { rc = gnutls_store_pubkey(NULL, NULL, hostname, txt_service, GNUTLS_CRT_X509, cert, 0, 0); if (rc < 0) fprintf(stderr, "Could not store key: %s\n", gnutls_strerror(rc)); } } return 0; }
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 cert_verify_callback (gnutls_session_t session) { int rc; unsigned int status = 0; int ssh = ENABLED_OPT(TOFU); #ifdef HAVE_DANE int dane = ENABLED_OPT(DANE); #endif int ca_verify = ENABLED_OPT(CA_VERIFICATION); const char* txt_service; print_cert_info (session, verbose, print_cert); if (ca_verify) { rc = cert_verify(session, hostname); if (rc == 0) { printf ("*** Verifying server certificate failed...\n"); if (!insecure && !ssh) return -1; } else if (ENABLED_OPT(OCSP) && gnutls_ocsp_status_request_is_checked(session, 0) == 0) { /* off-line verification succeeded. Try OCSP */ rc = cert_verify_ocsp(session); if (rc == 0) { printf ("*** Verifying (with OCSP) server certificate failed...\n"); if (!insecure && !ssh) return -1; } else if (rc == -1) printf("*** OCSP response ignored\n"); } } if (ssh) /* try ssh auth */ { unsigned int list_size; const gnutls_datum_t * cert; cert = gnutls_certificate_get_peers(session, &list_size); if (cert == NULL) { fprintf(stderr, "Cannot obtain peer's certificate!\n"); return -1; } txt_service = port_to_service(service); rc = gnutls_verify_stored_pubkey(NULL, NULL, hostname, txt_service, GNUTLS_CRT_X509, cert, 0); if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND) { print_cert_info_compact(session); fprintf(stderr, "Host %s (%s) has never been contacted before.\n", hostname, txt_service); if (status == 0) fprintf(stderr, "Its certificate is valid for %s.\n", hostname); rc = read_yesno("Are you sure you want to trust it? (y/N): "); if (rc == 0) return -1; } else if (rc == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { print_cert_info_compact(session); fprintf(stderr, "Warning: host %s is known and it is associated with a different key.\n", hostname); fprintf(stderr, "It might be that the server has multiple keys, or an attacker replaced the key to eavesdrop this connection .\n"); if (status == 0) fprintf(stderr, "Its certificate is valid for %s.\n", hostname); rc = read_yesno("Do you trust the received key? (y/N): "); if (rc == 0) return -1; } else if (rc < 0) { fprintf(stderr, "gnutls_verify_stored_pubkey: %s\n", gnutls_strerror(rc)); return -1; } if (rc != 0) { rc = gnutls_store_pubkey(NULL, NULL, hostname, txt_service, GNUTLS_CRT_X509, cert, 0, 0); if (rc < 0) fprintf(stderr, "Could not store key: %s\n", gnutls_strerror(rc)); } } #ifdef HAVE_DANE if (dane) /* try DANE auth */ { unsigned int sflags = ENABLED_OPT(LOCAL_DNS)?0:DANE_F_IGNORE_LOCAL_RESOLVER; rc = dane_verify_session_crt( NULL, session, hostname, udp?"udp":"tcp", atoi(service), sflags, 0, &status); if (rc < 0) { fprintf(stderr, "*** DANE verification error: %s\n", dane_strerror(rc)); if (!insecure) return -1; } else { gnutls_datum_t out; rc = dane_verification_status_print( status, &out, 0); if (rc < 0) { fprintf(stderr, "*** DANE error: %s\n", dane_strerror(rc)); if (!insecure) return -1; } fprintf(stderr, "- %s\n", out.data); gnutls_free(out.data); } } #endif return 0; }