1 /* $OpenBSD: tls_conninfo.c,v 1.11 2016/08/22 17:12:35 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->version); 252 conninfo->version = NULL; 253 254 free(conninfo->hash); 255 conninfo->hash = NULL; 256 free(conninfo->issuer); 257 conninfo->issuer = NULL; 258 free(conninfo->subject); 259 conninfo->subject = NULL; 260 261 free(conninfo); 262 } 263 264 const char * 265 tls_conn_alpn_selected(struct tls *ctx) 266 { 267 if (ctx->conninfo == NULL) 268 return (NULL); 269 return (ctx->conninfo->alpn); 270 } 271 272 const char * 273 tls_conn_cipher(struct tls *ctx) 274 { 275 if (ctx->conninfo == NULL) 276 return (NULL); 277 return (ctx->conninfo->cipher); 278 } 279 280 const char * 281 tls_conn_servername(struct tls *ctx) 282 { 283 if (ctx->conninfo == NULL) 284 return (NULL); 285 return (ctx->conninfo->servername); 286 } 287 288 const char * 289 tls_conn_version(struct tls *ctx) 290 { 291 if (ctx->conninfo == NULL) 292 return (NULL); 293 return (ctx->conninfo->version); 294 } 295