1 /* $OpenBSD: ssl_asn1.c,v 1.57 2018/08/27 16:42:48 jsing Exp $ */ 2 /* 3 * Copyright (c) 2016 Joel Sing <jsing@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 <limits.h> 19 20 #include <openssl/ssl.h> 21 #include <openssl/x509.h> 22 23 #include "ssl_locl.h" 24 25 #include "bytestring.h" 26 27 #define SSLASN1_TAG (CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC) 28 #define SSLASN1_TIME_TAG (SSLASN1_TAG | 1) 29 #define SSLASN1_TIMEOUT_TAG (SSLASN1_TAG | 2) 30 #define SSLASN1_PEER_CERT_TAG (SSLASN1_TAG | 3) 31 #define SSLASN1_SESSION_ID_CTX_TAG (SSLASN1_TAG | 4) 32 #define SSLASN1_VERIFY_RESULT_TAG (SSLASN1_TAG | 5) 33 #define SSLASN1_HOSTNAME_TAG (SSLASN1_TAG | 6) 34 #define SSLASN1_LIFETIME_TAG (SSLASN1_TAG | 9) 35 #define SSLASN1_TICKET_TAG (SSLASN1_TAG | 10) 36 37 static uint64_t 38 time_max(void) 39 { 40 if (sizeof(time_t) == sizeof(int32_t)) 41 return INT32_MAX; 42 if (sizeof(time_t) == sizeof(int64_t)) 43 return INT64_MAX; 44 return 0; 45 } 46 47 static int 48 SSL_SESSION_encode(SSL_SESSION *s, unsigned char **out, size_t *out_len, 49 int ticket_encoding) 50 { 51 CBB cbb, session, cipher_suite, session_id, master_key, time, timeout; 52 CBB peer_cert, sidctx, verify_result, hostname, lifetime, ticket, value; 53 unsigned char *peer_cert_bytes = NULL; 54 int len, rv = 0; 55 uint16_t cid; 56 57 if (!CBB_init(&cbb, 0)) 58 goto err; 59 60 if (!CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE)) 61 goto err; 62 63 /* Session ASN1 version. */ 64 if (!CBB_add_asn1_uint64(&session, SSL_SESSION_ASN1_VERSION)) 65 goto err; 66 67 /* TLS/SSL protocol version. */ 68 if (s->ssl_version < 0) 69 goto err; 70 if (!CBB_add_asn1_uint64(&session, s->ssl_version)) 71 goto err; 72 73 /* Cipher suite ID. */ 74 /* XXX - require cipher to be non-NULL or always/only use cipher_id. */ 75 cid = (uint16_t)(s->cipher_id & 0xffff); 76 if (s->cipher != NULL) 77 cid = ssl3_cipher_get_value(s->cipher); 78 if (!CBB_add_asn1(&session, &cipher_suite, CBS_ASN1_OCTETSTRING)) 79 goto err; 80 if (!CBB_add_u16(&cipher_suite, cid)) 81 goto err; 82 83 /* Session ID - zero length for a ticket. */ 84 if (!CBB_add_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING)) 85 goto err; 86 if (!CBB_add_bytes(&session_id, s->session_id, 87 ticket_encoding ? 0 : s->session_id_length)) 88 goto err; 89 90 /* Master key. */ 91 if (!CBB_add_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING)) 92 goto err; 93 if (!CBB_add_bytes(&master_key, s->master_key, s->master_key_length)) 94 goto err; 95 96 /* Time [1]. */ 97 if (s->time != 0) { 98 if (s->time < 0) 99 goto err; 100 if (!CBB_add_asn1(&session, &time, SSLASN1_TIME_TAG)) 101 goto err; 102 if (!CBB_add_asn1_uint64(&time, s->time)) 103 goto err; 104 } 105 106 /* Timeout [2]. */ 107 if (s->timeout != 0) { 108 if (s->timeout < 0) 109 goto err; 110 if (!CBB_add_asn1(&session, &timeout, SSLASN1_TIMEOUT_TAG)) 111 goto err; 112 if (!CBB_add_asn1_uint64(&timeout, s->timeout)) 113 goto err; 114 } 115 116 /* Peer certificate [3]. */ 117 if (s->peer != NULL) { 118 if ((len = i2d_X509(s->peer, &peer_cert_bytes)) <= 0) 119 goto err; 120 if (!CBB_add_asn1(&session, &peer_cert, SSLASN1_PEER_CERT_TAG)) 121 goto err; 122 if (!CBB_add_bytes(&peer_cert, peer_cert_bytes, len)) 123 goto err; 124 } 125 126 /* Session ID context [4]. */ 127 /* XXX - Actually handle this as optional? */ 128 if (!CBB_add_asn1(&session, &sidctx, SSLASN1_SESSION_ID_CTX_TAG)) 129 goto err; 130 if (!CBB_add_asn1(&sidctx, &value, CBS_ASN1_OCTETSTRING)) 131 goto err; 132 if (!CBB_add_bytes(&value, s->sid_ctx, s->sid_ctx_length)) 133 goto err; 134 135 /* Verify result [5]. */ 136 if (s->verify_result != X509_V_OK) { 137 if (s->verify_result < 0) 138 goto err; 139 if (!CBB_add_asn1(&session, &verify_result, 140 SSLASN1_VERIFY_RESULT_TAG)) 141 goto err; 142 if (!CBB_add_asn1_uint64(&verify_result, s->verify_result)) 143 goto err; 144 } 145 146 /* Hostname [6]. */ 147 if (s->tlsext_hostname != NULL) { 148 if (!CBB_add_asn1(&session, &hostname, SSLASN1_HOSTNAME_TAG)) 149 goto err; 150 if (!CBB_add_asn1(&hostname, &value, CBS_ASN1_OCTETSTRING)) 151 goto err; 152 if (!CBB_add_bytes(&value, (const uint8_t *)s->tlsext_hostname, 153 strlen(s->tlsext_hostname))) 154 goto err; 155 } 156 157 /* PSK identity hint [7]. */ 158 /* PSK identity [8]. */ 159 160 /* Ticket lifetime hint [9]. */ 161 if (s->tlsext_tick_lifetime_hint > 0) { 162 if (!CBB_add_asn1(&session, &lifetime, SSLASN1_LIFETIME_TAG)) 163 goto err; 164 if (!CBB_add_asn1_uint64(&lifetime, 165 s->tlsext_tick_lifetime_hint)) 166 goto err; 167 } 168 169 /* Ticket [10]. */ 170 if (s->tlsext_tick != NULL) { 171 if (!CBB_add_asn1(&session, &ticket, SSLASN1_TICKET_TAG)) 172 goto err; 173 if (!CBB_add_asn1(&ticket, &value, CBS_ASN1_OCTETSTRING)) 174 goto err; 175 if (!CBB_add_bytes(&value, s->tlsext_tick, s->tlsext_ticklen)) 176 goto err; 177 } 178 179 /* Compression method [11]. */ 180 /* SRP username [12]. */ 181 182 if (!CBB_finish(&cbb, out, out_len)) 183 goto err; 184 185 rv = 1; 186 187 err: 188 CBB_cleanup(&cbb); 189 free(peer_cert_bytes); 190 191 return rv; 192 } 193 194 int 195 SSL_SESSION_ticket(SSL_SESSION *ss, unsigned char **out, size_t *out_len) 196 { 197 if (ss == NULL) 198 return 0; 199 200 if (ss->cipher == NULL && ss->cipher_id == 0) 201 return 0; 202 203 return SSL_SESSION_encode(ss, out, out_len, 1); 204 } 205 206 int 207 i2d_SSL_SESSION(SSL_SESSION *ss, unsigned char **pp) 208 { 209 unsigned char *data = NULL; 210 size_t data_len = 0; 211 int rv = -1; 212 213 if (ss == NULL) 214 return 0; 215 216 if (ss->cipher == NULL && ss->cipher_id == 0) 217 return 0; 218 219 if (!SSL_SESSION_encode(ss, &data, &data_len, 0)) 220 goto err; 221 222 if (data_len > INT_MAX) 223 goto err; 224 225 if (pp != NULL) { 226 if (*pp == NULL) { 227 *pp = data; 228 data = NULL; 229 } else { 230 memcpy(*pp, data, data_len); 231 *pp += data_len; 232 } 233 } 234 235 rv = (int)data_len; 236 237 err: 238 freezero(data, data_len); 239 240 return rv; 241 } 242 243 SSL_SESSION * 244 d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length) 245 { 246 CBS cbs, session, cipher_suite, session_id, master_key, peer_cert; 247 CBS hostname, ticket; 248 uint64_t version, tls_version, stime, timeout, verify_result, lifetime; 249 const unsigned char *peer_cert_bytes; 250 uint16_t cipher_value; 251 SSL_SESSION *s = NULL; 252 size_t data_len; 253 int present; 254 255 if (a != NULL) 256 s = *a; 257 258 if (s == NULL) { 259 if ((s = SSL_SESSION_new()) == NULL) { 260 SSLerrorx(ERR_R_MALLOC_FAILURE); 261 return (NULL); 262 } 263 } 264 265 CBS_init(&cbs, *pp, length); 266 267 if (!CBS_get_asn1(&cbs, &session, CBS_ASN1_SEQUENCE)) 268 goto err; 269 270 /* Session ASN1 version. */ 271 if (!CBS_get_asn1_uint64(&session, &version)) 272 goto err; 273 if (version != SSL_SESSION_ASN1_VERSION) 274 goto err; 275 276 /* TLS/SSL Protocol Version. */ 277 if (!CBS_get_asn1_uint64(&session, &tls_version)) 278 goto err; 279 if (tls_version > INT_MAX) 280 goto err; 281 s->ssl_version = (int)tls_version; 282 283 /* Cipher suite. */ 284 if (!CBS_get_asn1(&session, &cipher_suite, CBS_ASN1_OCTETSTRING)) 285 goto err; 286 if (!CBS_get_u16(&cipher_suite, &cipher_value)) 287 goto err; 288 if (CBS_len(&cipher_suite) != 0) 289 goto err; 290 291 /* XXX - populate cipher instead? */ 292 s->cipher = NULL; 293 s->cipher_id = SSL3_CK_ID | cipher_value; 294 295 /* Session ID. */ 296 if (!CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING)) 297 goto err; 298 if (!CBS_write_bytes(&session_id, s->session_id, sizeof(s->session_id), 299 &data_len)) 300 goto err; 301 if (data_len > UINT_MAX) 302 goto err; 303 s->session_id_length = (unsigned int)data_len; 304 305 /* Master key. */ 306 if (!CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING)) 307 goto err; 308 if (!CBS_write_bytes(&master_key, s->master_key, sizeof(s->master_key), 309 &data_len)) 310 goto err; 311 if (data_len > INT_MAX) 312 goto err; 313 s->master_key_length = (int)data_len; 314 315 /* Time [1]. */ 316 s->time = time(NULL); 317 if (!CBS_get_optional_asn1_uint64(&session, &stime, SSLASN1_TIME_TAG, 318 0)) 319 goto err; 320 if (stime > time_max()) 321 goto err; 322 if (stime != 0) 323 s->time = (time_t)stime; 324 325 /* Timeout [2]. */ 326 s->timeout = 3; 327 if (!CBS_get_optional_asn1_uint64(&session, &timeout, 328 SSLASN1_TIMEOUT_TAG, 0)) 329 goto err; 330 if (timeout > LONG_MAX) 331 goto err; 332 if (timeout != 0) 333 s->timeout = (long)timeout; 334 335 /* Peer certificate [3]. */ 336 X509_free(s->peer); 337 s->peer = NULL; 338 if (!CBS_get_optional_asn1(&session, &peer_cert, &present, 339 SSLASN1_PEER_CERT_TAG)) 340 goto err; 341 if (present) { 342 data_len = CBS_len(&peer_cert); 343 if (data_len > LONG_MAX) 344 goto err; 345 peer_cert_bytes = CBS_data(&peer_cert); 346 if (d2i_X509(&s->peer, &peer_cert_bytes, 347 (long)data_len) == NULL) 348 goto err; 349 } 350 351 /* Session ID context [4]. */ 352 s->sid_ctx_length = 0; 353 if (!CBS_get_optional_asn1_octet_string(&session, &session_id, &present, 354 SSLASN1_SESSION_ID_CTX_TAG)) 355 goto err; 356 if (present) { 357 if (!CBS_write_bytes(&session_id, (uint8_t *)&s->sid_ctx, 358 sizeof(s->sid_ctx), &data_len)) 359 goto err; 360 if (data_len > UINT_MAX) 361 goto err; 362 s->sid_ctx_length = (unsigned int)data_len; 363 } 364 365 /* Verify result [5]. */ 366 s->verify_result = X509_V_OK; 367 if (!CBS_get_optional_asn1_uint64(&session, &verify_result, 368 SSLASN1_VERIFY_RESULT_TAG, X509_V_OK)) 369 goto err; 370 if (verify_result > LONG_MAX) 371 goto err; 372 s->verify_result = (long)verify_result; 373 374 /* Hostname [6]. */ 375 free(s->tlsext_hostname); 376 s->tlsext_hostname = NULL; 377 if (!CBS_get_optional_asn1_octet_string(&session, &hostname, &present, 378 SSLASN1_HOSTNAME_TAG)) 379 goto err; 380 if (present) { 381 if (CBS_contains_zero_byte(&hostname)) 382 goto err; 383 if (!CBS_strdup(&hostname, &s->tlsext_hostname)) 384 goto err; 385 } 386 387 /* PSK identity hint [7]. */ 388 /* PSK identity [8]. */ 389 390 /* Ticket lifetime [9]. */ 391 s->tlsext_tick_lifetime_hint = 0; 392 /* XXX - tlsext_ticklen is not yet set... */ 393 if (s->tlsext_ticklen > 0 && s->session_id_length > 0) 394 s->tlsext_tick_lifetime_hint = -1; 395 if (!CBS_get_optional_asn1_uint64(&session, &lifetime, 396 SSLASN1_LIFETIME_TAG, 0)) 397 goto err; 398 if (lifetime > LONG_MAX) 399 goto err; 400 if (lifetime > 0) 401 s->tlsext_tick_lifetime_hint = (long)lifetime; 402 403 /* Ticket [10]. */ 404 free(s->tlsext_tick); 405 s->tlsext_tick = NULL; 406 if (!CBS_get_optional_asn1_octet_string(&session, &ticket, &present, 407 SSLASN1_TICKET_TAG)) 408 goto err; 409 if (present) { 410 if (!CBS_stow(&ticket, &s->tlsext_tick, &s->tlsext_ticklen)) 411 goto err; 412 } 413 414 /* Compression method [11]. */ 415 /* SRP username [12]. */ 416 417 *pp = CBS_data(&cbs); 418 419 if (a != NULL) 420 *a = s; 421 422 return (s); 423 424 err: 425 ERR_asprintf_error_data("offset=%d", (int)(CBS_data(&cbs) - *pp)); 426 427 if (s != NULL && (a == NULL || *a != s)) 428 SSL_SESSION_free(s); 429 430 return (NULL); 431 } 432