1 /* $OpenBSD: tls_conninfo.c,v 1.4 2015/10/07 23:25:45 beck Exp $ */ 2 /* 3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org> 4 * Copyright (c) 2015 Bob Beck <beck@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <stdio.h> 20 21 #include <openssl/x509.h> 22 23 #include <tls.h> 24 #include "tls_internal.h" 25 26 static int 27 tls_hex_string(const unsigned char *in, size_t inlen, char **out, 28 size_t *outlen) 29 { 30 static const char hex[] = "0123456789abcdef"; 31 size_t i, len; 32 char *p; 33 34 if (outlen != NULL) 35 *outlen = 0; 36 37 if (inlen >= SIZE_MAX) 38 return (-1); 39 if ((*out = reallocarray(NULL, inlen + 1, 2)) == NULL) 40 return (-1); 41 42 p = *out; 43 len = 0; 44 for (i = 0; i < inlen; i++) { 45 p[len++] = hex[(in[i] >> 4) & 0x0f]; 46 p[len++] = hex[in[i] & 0x0f]; 47 } 48 p[len++] = 0; 49 50 if (outlen != NULL) 51 *outlen = len; 52 53 return (0); 54 } 55 56 static int 57 tls_get_peer_cert_hash(struct tls *ctx, char **hash) 58 { 59 char d[EVP_MAX_MD_SIZE], *dhex = NULL; 60 int dlen, rv = -1; 61 62 *hash = NULL; 63 if (ctx->ssl_peer_cert == NULL) 64 return (0); 65 66 if (X509_digest(ctx->ssl_peer_cert, EVP_sha256(), d, &dlen) != 1) { 67 tls_set_errorx(ctx, "digest failed"); 68 goto err; 69 } 70 71 if (tls_hex_string(d, dlen, &dhex, NULL) != 0) { 72 tls_set_errorx(ctx, "digest hex string failed"); 73 goto err; 74 } 75 76 if (asprintf(hash, "SHA256:%s", dhex) == -1) { 77 tls_set_errorx(ctx, "out of memory"); 78 *hash = NULL; 79 goto err; 80 } 81 82 rv = 0; 83 84 err: 85 free(dhex); 86 87 return (rv); 88 } 89 90 static int 91 tls_get_peer_cert_issuer(struct tls *ctx, char **issuer) 92 { 93 X509_NAME *name = NULL; 94 95 *issuer = NULL; 96 if (ctx->ssl_peer_cert == NULL) 97 return (-1); 98 if ((name = X509_get_issuer_name(ctx->ssl_peer_cert)) == NULL) 99 return (-1); 100 *issuer = X509_NAME_oneline(name, 0, 0); 101 if (*issuer == NULL) 102 return (-1); 103 return (0); 104 } 105 106 static int 107 tls_get_peer_cert_subject(struct tls *ctx, char **subject) 108 { 109 X509_NAME *name = NULL; 110 111 *subject = NULL; 112 if (ctx->ssl_peer_cert == NULL) 113 return (-1); 114 if ((name = X509_get_subject_name(ctx->ssl_peer_cert)) == NULL) 115 return (-1); 116 *subject = X509_NAME_oneline(name, 0, 0); 117 if (*subject == NULL) 118 return (-1); 119 return (0); 120 } 121 122 static int 123 tls_get_peer_cert_times(struct tls *ctx, time_t *notbefore, time_t *notafter) 124 { 125 struct tm before_tm, after_tm; 126 ASN1_TIME *before, *after; 127 int rv = -1; 128 129 memset(&before_tm, 0, sizeof(before_tm)); 130 memset(&after_tm, 0, sizeof(after_tm)); 131 132 if (ctx->ssl_peer_cert != NULL) { 133 if ((before = X509_get_notBefore(ctx->ssl_peer_cert)) == NULL) 134 goto err; 135 if ((after = X509_get_notAfter(ctx->ssl_peer_cert)) == NULL) 136 goto err; 137 if (asn1_time_parse(before->data, before->length, &before_tm, 0) 138 == -1) 139 goto err; 140 if (asn1_time_parse(after->data, after->length, &after_tm, 0) 141 == -1) 142 goto err; 143 if ((*notbefore = timegm(&before_tm)) == -1) 144 goto err; 145 if ((*notafter = timegm(&after_tm)) == -1) 146 goto err; 147 } 148 rv = 0; 149 err: 150 return (rv); 151 } 152 153 int 154 tls_get_conninfo(struct tls *ctx) { 155 const char * tmp; 156 if (ctx->ssl_peer_cert != NULL) { 157 if (tls_get_peer_cert_hash(ctx, &ctx->conninfo->hash) == -1) 158 goto err; 159 if (tls_get_peer_cert_subject(ctx, &ctx->conninfo->subject) 160 == -1) 161 goto err; 162 if (tls_get_peer_cert_issuer(ctx, &ctx->conninfo->issuer) == -1) 163 goto err; 164 if (tls_get_peer_cert_times(ctx, &ctx->conninfo->notbefore, 165 &ctx->conninfo->notafter) == -1) 166 goto err; 167 } 168 if ((tmp = SSL_get_version(ctx->ssl_conn)) == NULL) 169 goto err; 170 ctx->conninfo->version = strdup(tmp); 171 if (ctx->conninfo->version == NULL) 172 goto err; 173 if ((tmp = SSL_get_cipher(ctx->ssl_conn)) == NULL) 174 goto err; 175 ctx->conninfo->cipher = strdup(tmp); 176 if (ctx->conninfo->cipher == NULL) 177 goto err; 178 return (0); 179 err: 180 tls_free_conninfo(ctx->conninfo); 181 return (-1); 182 } 183 184 void 185 tls_free_conninfo(struct tls_conninfo *conninfo) { 186 if (conninfo != NULL) { 187 free(conninfo->hash); 188 conninfo->hash = NULL; 189 free(conninfo->subject); 190 conninfo->subject = NULL; 191 free(conninfo->issuer); 192 conninfo->issuer = NULL; 193 free(conninfo->version); 194 conninfo->version = NULL; 195 free(conninfo->cipher); 196 conninfo->cipher = NULL; 197 } 198 } 199 200 const char * 201 tls_conn_cipher(struct tls *ctx) 202 { 203 if (ctx->conninfo == NULL) 204 return (NULL); 205 return (ctx->conninfo->cipher); 206 } 207 208 const char * 209 tls_conn_version(struct tls *ctx) 210 { 211 if (ctx->conninfo == NULL) 212 return (NULL); 213 return (ctx->conninfo->version); 214 } 215