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