1 /* $OpenBSD: ocsp_test.c,v 1.6 2018/07/18 16:24:16 tb Exp $ */ 2 /* 3 * Copyright (c) 2016 Bob Beck <beck@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <stdio.h> 19 #include <netdb.h> 20 #include <stdlib.h> 21 #include <unistd.h> 22 #include <err.h> 23 #include <sys/socket.h> 24 25 #include <openssl/ssl.h> 26 #include <openssl/ocsp.h> 27 28 static int 29 tcp_connect(char *host, char *port) 30 { 31 int error, sd = -1; 32 struct addrinfo hints, *res, *r; 33 34 memset(&hints, 0, sizeof(struct addrinfo)); 35 hints.ai_family = AF_INET; 36 hints.ai_socktype = SOCK_STREAM; 37 38 error = getaddrinfo(host, port, &hints, &res); 39 if (error != 0) { 40 perror("getaddrinfo()"); 41 exit(-1); 42 } 43 44 for (r = res; r != NULL; r = r->ai_next) { 45 sd = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 46 if (sd == -1) 47 continue; 48 49 if (connect(sd, r->ai_addr, r->ai_addrlen) == 0) 50 break; 51 52 close(sd); 53 } 54 55 freeaddrinfo(res); 56 57 return sd; 58 } 59 60 int 61 main(int argc, char *argv[]) 62 { 63 int sd, ocsp_status; 64 const unsigned char *p; 65 long len; 66 OCSP_RESPONSE *rsp = NULL; 67 OCSP_BASICRESP *br = NULL; 68 X509_STORE *st = NULL; 69 STACK_OF(X509) *ch = NULL; 70 char *host, *port; 71 #ifdef _PATH_SSL_CA_FILE 72 char *cafile = _PATH_SSL_CA_FILE; 73 #else 74 char *cafile = "/etc/ssl/cert.pem"; 75 #endif 76 77 SSL *ssl; 78 SSL_CTX *ctx; 79 80 SSL_library_init(); 81 SSL_load_error_strings(); 82 83 ctx = SSL_CTX_new(SSLv23_client_method()); 84 85 if (!SSL_CTX_load_verify_locations(ctx, cafile, NULL)) { 86 printf("failed to load %s\n", cafile); 87 exit(-1); 88 } 89 90 if (argc != 3) 91 errx(-1, "need a host and port to connect to"); 92 else { 93 host = argv[1]; 94 port = argv[2]; 95 } 96 97 sd = tcp_connect(host, port); 98 99 ssl = SSL_new(ctx); 100 101 SSL_set_fd(ssl, (int) sd); 102 SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp); 103 104 if (SSL_connect(ssl) <= 0) { 105 printf("SSL connect error\n"); 106 exit(-1); 107 } 108 109 if (SSL_get_verify_result(ssl) != X509_V_OK) { 110 printf("Certificate doesn't verify from host %s port %s\n", host, port); 111 exit(-1); 112 } 113 114 /* ==== VERIFY OCSP RESPONSE ==== */ 115 116 117 len = SSL_get_tlsext_status_ocsp_resp(ssl, &p); 118 119 if (!p) { 120 printf("No OCSP response received for %s port %s\n", host, port); 121 exit(-1); 122 } 123 124 rsp = d2i_OCSP_RESPONSE(NULL, &p, len); 125 if (!rsp) { 126 puts("Invalid OCSP response"); 127 exit(-1); 128 } 129 130 ocsp_status = OCSP_response_status(rsp); 131 if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { 132 printf("Invalid OCSP response status: %s (%d)", 133 OCSP_response_status_str(ocsp_status), ocsp_status); 134 exit(-1); 135 } 136 137 br = OCSP_response_get1_basic(rsp); 138 if (!br) { 139 puts("Invalid OCSP response"); 140 exit(-1); 141 } 142 143 ch = SSL_get_peer_cert_chain(ssl); 144 st = SSL_CTX_get_cert_store(ctx); 145 146 if (OCSP_basic_verify(br, ch, st, 0) <= 0) { 147 puts("OCSP response verification failed"); 148 exit(-1); 149 } 150 151 printf("OCSP validated from %s %s\n", host, port); 152 153 return 0; 154 } 155