/* SSL_SESSION_parse_string gets an optional ASN.1 OCTET STRING * explicitly tagged with |tag| from |cbs| and saves it in |*out|. On * entry, if |*out| is not NULL, it frees the existing contents. If * the element was not found, it sets |*out| to NULL. It returns one * on success, whether or not the element was found, and zero on * decode error. */ static int SSL_SESSION_parse_string(CBS *cbs, char **out, unsigned tag) { CBS value; int present; if (!CBS_get_optional_asn1_octet_string(cbs, &value, &present, tag)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); return 0; } if (present) { if (CBS_contains_zero_byte(&value)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); return 0; } if (!CBS_strdup(&value, out)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return 0; } } else { OPENSSL_free(*out); *out = NULL; } 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); }