1 /* $OpenBSD: tls_conninfo.c,v 1.13 2017/01/09 15:31:20 jsing 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, 124 time_t *notafter) 125 { 126 struct tm before_tm, after_tm; 127 ASN1_TIME *before, *after; 128 129 if (ctx->ssl_peer_cert == NULL) 130 return (-1); 131 132 memset(&before_tm, 0, sizeof(before_tm)); 133 memset(&after_tm, 0, sizeof(after_tm)); 134 135 if ((before = X509_get_notBefore(ctx->ssl_peer_cert)) == NULL) 136 goto err; 137 if ((after = X509_get_notAfter(ctx->ssl_peer_cert)) == NULL) 138 goto err; 139 if (ASN1_time_parse(before->data, before->length, &before_tm, 0) == -1) 140 goto err; 141 if (ASN1_time_parse(after->data, after->length, &after_tm, 0) == -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 return (0); 149 150 err: 151 return (-1); 152 } 153 154 static int 155 tls_get_peer_cert_info(struct tls *ctx) 156 { 157 if (ctx->ssl_peer_cert == NULL) 158 return (0); 159 160 if (tls_get_peer_cert_hash(ctx, &ctx->conninfo->hash) == -1) 161 goto err; 162 if (tls_get_peer_cert_subject(ctx, &ctx->conninfo->subject) == -1) 163 goto err; 164 if (tls_get_peer_cert_issuer(ctx, &ctx->conninfo->issuer) == -1) 165 goto err; 166 if (tls_get_peer_cert_times(ctx, &ctx->conninfo->notbefore, 167 &ctx->conninfo->notafter) == -1) 168 goto err; 169 170 return (0); 171 172 err: 173 return (-1); 174 } 175 176 static int 177 tls_conninfo_alpn_proto(struct tls *ctx) 178 { 179 const unsigned char *p; 180 unsigned int len; 181 182 free(ctx->conninfo->alpn); 183 ctx->conninfo->alpn = NULL; 184 185 SSL_get0_alpn_selected(ctx->ssl_conn, &p, &len); 186 if (len > 0) { 187 if ((ctx->conninfo->alpn = malloc(len + 1)) == NULL) 188 return (-1); 189 memcpy(ctx->conninfo->alpn, p, len); 190 ctx->conninfo->alpn[len] = '\0'; 191 } 192 193 return (0); 194 } 195 196 int 197 tls_conninfo_populate(struct tls *ctx) 198 { 199 const char *tmp; 200 201 tls_conninfo_free(ctx->conninfo); 202 203 if ((ctx->conninfo = calloc(1, sizeof(struct tls_conninfo))) == NULL) { 204 tls_set_errorx(ctx, "out of memory"); 205 goto err; 206 } 207 208 if (tls_conninfo_alpn_proto(ctx) == -1) 209 goto err; 210 211 if ((tmp = SSL_get_cipher(ctx->ssl_conn)) == NULL) 212 goto err; 213 ctx->conninfo->cipher = strdup(tmp); 214 if (ctx->conninfo->cipher == NULL) 215 goto err; 216 217 if (ctx->servername != NULL) { 218 if ((ctx->conninfo->servername = 219 strdup(ctx->servername)) == NULL) 220 goto err; 221 } 222 223 if ((tmp = SSL_get_version(ctx->ssl_conn)) == NULL) 224 goto err; 225 ctx->conninfo->version = strdup(tmp); 226 if (ctx->conninfo->version == NULL) 227 goto err; 228 229 if (tls_get_peer_cert_info(ctx) == -1) 230 goto err; 231 232 return (0); 233 234 err: 235 tls_conninfo_free(ctx->conninfo); 236 ctx->conninfo = NULL; 237 238 return (-1); 239 } 240 241 void 242 tls_conninfo_free(struct tls_conninfo *conninfo) 243 { 244 if (conninfo == NULL) 245 return; 246 247 free(conninfo->alpn); 248 conninfo->alpn = NULL; 249 free(conninfo->cipher); 250 conninfo->cipher = NULL; 251 free(conninfo->servername); 252 conninfo->servername = NULL; 253 free(conninfo->version); 254 conninfo->version = NULL; 255 256 free(conninfo->hash); 257 conninfo->hash = NULL; 258 free(conninfo->issuer); 259 conninfo->issuer = NULL; 260 free(conninfo->subject); 261 conninfo->subject = NULL; 262 263 free(conninfo); 264 } 265 266 const char * 267 tls_conn_alpn_selected(struct tls *ctx) 268 { 269 if (ctx->conninfo == NULL) 270 return (NULL); 271 return (ctx->conninfo->alpn); 272 } 273 274 const char * 275 tls_conn_cipher(struct tls *ctx) 276 { 277 if (ctx->conninfo == NULL) 278 return (NULL); 279 return (ctx->conninfo->cipher); 280 } 281 282 const char * 283 tls_conn_servername(struct tls *ctx) 284 { 285 if (ctx->conninfo == NULL) 286 return (NULL); 287 return (ctx->conninfo->servername); 288 } 289 290 const char * 291 tls_conn_version(struct tls *ctx) 292 { 293 if (ctx->conninfo == NULL) 294 return (NULL); 295 return (ctx->conninfo->version); 296 } 297