static int SSL_SESSION_parse_u16(CBS *cbs, uint16_t *out, unsigned tag, uint16_t default_value) { uint64_t value; if (!CBS_get_optional_asn1_uint64(cbs, &value, tag, (uint64_t)default_value) || value > 0xffff) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); return 0; } *out = (uint16_t)value; return 1; }
static int SSL_SESSION_parse_long(CBS *cbs, long *out, unsigned tag, long default_value) { uint64_t value; if (!CBS_get_optional_asn1_uint64(cbs, &value, tag, (uint64_t)default_value) || value > LONG_MAX) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); return 0; } *out = (long)value; return 1; }
SSL_SESSION * d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length) { CBS cbs, session, cipher_suite, session_id, master_key, peer_cert; CBS hostname, ticket; uint64_t version, tls_version, stime, timeout, verify_result, lifetime; const unsigned char *peer_cert_bytes; uint16_t cipher_value; SSL_SESSION *s = NULL; size_t data_len; int present; if (a != NULL) s = *a; if (s == NULL) { if ((s = SSL_SESSION_new()) == NULL) { SSLerrorx(ERR_R_MALLOC_FAILURE); return (NULL); } } CBS_init(&cbs, *pp, length); if (!CBS_get_asn1(&cbs, &session, CBS_ASN1_SEQUENCE)) goto err; /* Session ASN1 version. */ if (!CBS_get_asn1_uint64(&session, &version)) goto err; if (version != SSL_SESSION_ASN1_VERSION) goto err; /* TLS/SSL Protocol Version. */ if (!CBS_get_asn1_uint64(&session, &tls_version)) goto err; if (tls_version > INT_MAX) goto err; s->ssl_version = (int)tls_version; /* Cipher suite. */ if (!CBS_get_asn1(&session, &cipher_suite, CBS_ASN1_OCTETSTRING)) goto err; if (!CBS_get_u16(&cipher_suite, &cipher_value)) goto err; if (CBS_len(&cipher_suite) != 0) goto err; /* XXX - populate cipher instead? */ s->cipher = NULL; s->cipher_id = SSL3_CK_ID | cipher_value; /* Session ID. */ if (!CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING)) goto err; if (!CBS_write_bytes(&session_id, s->session_id, sizeof(s->session_id), &data_len)) goto err; if (data_len > UINT_MAX) goto err; s->session_id_length = (unsigned int)data_len; /* Master key. */ if (!CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING)) goto err; if (!CBS_write_bytes(&master_key, s->master_key, sizeof(s->master_key), &data_len)) goto err; if (data_len > INT_MAX) goto err; s->master_key_length = (int)data_len; /* Time [1]. */ s->time = time(NULL); if (!CBS_get_optional_asn1_uint64(&session, &stime, SSLASN1_TIME_TAG, 0)) goto err; if (stime > time_max()) goto err; if (stime != 0) s->time = (time_t)stime; /* Timeout [2]. */ s->timeout = 3; if (!CBS_get_optional_asn1_uint64(&session, &timeout, SSLASN1_TIMEOUT_TAG, 0)) goto err; if (timeout > LONG_MAX) goto err; if (timeout != 0) s->timeout = (long)timeout; /* Peer certificate [3]. */ X509_free(s->peer); s->peer = NULL; if (!CBS_get_optional_asn1(&session, &peer_cert, &present, SSLASN1_PEER_CERT_TAG)) goto err; if (present) { data_len = CBS_len(&peer_cert); if (data_len > LONG_MAX) goto err; peer_cert_bytes = CBS_data(&peer_cert); if (d2i_X509(&s->peer, &peer_cert_bytes, (long)data_len) == NULL) goto err; } /* Session ID context [4]. */ s->sid_ctx_length = 0; if (!CBS_get_optional_asn1_octet_string(&session, &session_id, &present, SSLASN1_SESSION_ID_CTX_TAG)) goto err; if (present) { if (!CBS_write_bytes(&session_id, (uint8_t *)&s->sid_ctx, sizeof(s->sid_ctx), &data_len)) goto err; if (data_len > UINT_MAX) goto err; s->sid_ctx_length = (unsigned int)data_len; } /* Verify result [5]. */ s->verify_result = X509_V_OK; if (!CBS_get_optional_asn1_uint64(&session, &verify_result, SSLASN1_VERIFY_RESULT_TAG, X509_V_OK)) goto err; if (verify_result > LONG_MAX) goto err; s->verify_result = (long)verify_result; /* Hostname [6]. */ free(s->tlsext_hostname); s->tlsext_hostname = NULL; if (!CBS_get_optional_asn1_octet_string(&session, &hostname, &present, SSLASN1_HOSTNAME_TAG)) goto err; if (present) { if (CBS_contains_zero_byte(&hostname)) goto err; if (!CBS_strdup(&hostname, &s->tlsext_hostname)) goto err; } /* PSK identity hint [7]. */ /* PSK identity [8]. */ /* Ticket lifetime [9]. */ s->tlsext_tick_lifetime_hint = 0; /* XXX - tlsext_ticklen is not yet set... */ if (s->tlsext_ticklen > 0 && s->session_id_length > 0) s->tlsext_tick_lifetime_hint = -1; if (!CBS_get_optional_asn1_uint64(&session, &lifetime, SSLASN1_LIFETIME_TAG, 0)) goto err; if (lifetime > LONG_MAX) goto err; if (lifetime > 0) s->tlsext_tick_lifetime_hint = (long)lifetime; /* Ticket [10]. */ free(s->tlsext_tick); s->tlsext_tick = NULL; if (!CBS_get_optional_asn1_octet_string(&session, &ticket, &present, SSLASN1_TICKET_TAG)) goto err; if (present) { if (!CBS_stow(&ticket, &s->tlsext_tick, &s->tlsext_ticklen)) goto err; } /* Compression method [11]. */ /* SRP username [12]. */ *pp = CBS_data(&cbs); if (a != NULL) *a = s; return (s); err: ERR_asprintf_error_data("offset=%d", (int)(CBS_data(&cbs) - *pp)); if (s != NULL && (a == NULL || *a != s)) SSL_SESSION_free(s); return (NULL); }
static int test_get_asn1(void) { static const uint8_t kData1[] = {0x30, 2, 1, 2}; static const uint8_t kData2[] = {0x30, 3, 1, 2}; static const uint8_t kData3[] = {0x30, 0x80}; static const uint8_t kData4[] = {0x30, 0x81, 1, 1}; static const uint8_t kData5[] = {0x30, 0x82, 0, 1, 1}; static const uint8_t kData6[] = {0xa1, 3, 0x4, 1, 1}; static const uint8_t kData7[] = {0xa1, 3, 0x4, 2, 1}; static const uint8_t kData8[] = {0xa1, 3, 0x2, 1, 1}; static const uint8_t kData9[] = {0xa1, 3, 0x2, 1, 0xff}; CBS data, contents; int present; uint64_t value; CBS_init(&data, kData1, sizeof(kData1)); if (CBS_peek_asn1_tag(&data, 0x1) || !CBS_peek_asn1_tag(&data, 0x30)) { return 0; } if (!CBS_get_asn1(&data, &contents, 0x30) || CBS_len(&contents) != 2 || memcmp(CBS_data(&contents), "\x01\x02", 2) != 0) { return 0; } CBS_init(&data, kData2, sizeof(kData2)); /* data is truncated */ if (CBS_get_asn1(&data, &contents, 0x30)) { return 0; } CBS_init(&data, kData3, sizeof(kData3)); /* zero byte length of length */ if (CBS_get_asn1(&data, &contents, 0x30)) { return 0; } CBS_init(&data, kData4, sizeof(kData4)); /* long form mistakenly used. */ if (CBS_get_asn1(&data, &contents, 0x30)) { return 0; } CBS_init(&data, kData5, sizeof(kData5)); /* length takes too many bytes. */ if (CBS_get_asn1(&data, &contents, 0x30)) { return 0; } CBS_init(&data, kData1, sizeof(kData1)); /* wrong tag. */ if (CBS_get_asn1(&data, &contents, 0x31)) { return 0; } CBS_init(&data, NULL, 0); /* peek at empty data. */ if (CBS_peek_asn1_tag(&data, 0x30)) { return 0; } CBS_init(&data, NULL, 0); /* optional elements at empty data. */ if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) || present || !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) || present || CBS_len(&contents) != 0 || !CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0) || CBS_len(&contents) != 0 || !CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) || value != 42) { return 0; } CBS_init(&data, kData6, sizeof(kData6)); /* optional element. */ if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) || present || !CBS_get_optional_asn1(&data, &contents, &present, 0xa1) || !present || CBS_len(&contents) != 3 || memcmp(CBS_data(&contents), "\x04\x01\x01", 3) != 0) { return 0; } CBS_init(&data, kData6, sizeof(kData6)); /* optional octet string. */ if (!CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) || present || CBS_len(&contents) != 0 || !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1) || !present || CBS_len(&contents) != 1 || CBS_data(&contents)[0] != 1) { return 0; } CBS_init(&data, kData7, sizeof(kData7)); /* invalid optional octet string. */ if (CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1)) { return 0; } CBS_init(&data, kData8, sizeof(kData8)); /* optional octet string. */ if (!CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) || value != 42 || !CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42) || value != 1) { return 0; } CBS_init(&data, kData9, sizeof(kData9)); /* invalid optional integer. */ if (CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)) { return 0; } return 1; }