/* Finds an issuer of the certificate. If multiple issuers * are present, returns one that is activated and not expired. */ static inline gnutls_x509_crt_t find_issuer (gnutls_x509_crt_t cert, const gnutls_x509_crt_t * trusted_cas, int tcas_size) { int i; gnutls_x509_crt_t issuer = NULL; /* this is serial search. */ for (i = 0; i < tcas_size; i++) { if (is_issuer (cert, trusted_cas[i]) == 1) { if (issuer == NULL) { issuer = trusted_cas[i]; } else { time_t now = gnutls_time(0); if (now < gnutls_x509_crt_get_expiration_time(trusted_cas[i]) && now >= gnutls_x509_crt_get_activation_time(trusted_cas[i])) { issuer = trusted_cas[i]; } } } } return issuer; }
/* Returns the base64 key if found */ static int verify_pubkey(const char* file, const char* host, const char* service, const gnutls_datum_t* pubkey) { FILE* fd; char* line = NULL; size_t line_size = 0; int ret, l2, mismatch = 0; size_t host_len = 0, service_len = 0; time_t now = gnutls_time(0); gnutls_datum_t b64key = { NULL, 0 }; ret = raw_pubkey_to_base64(pubkey, &b64key); if (ret < 0) return gnutls_assert_val(ret); if (host != NULL) host_len = strlen(host); if (service != NULL) service_len = strlen(service); fd = fopen(file, "rb"); if (fd == NULL) { ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR); goto cleanup; } do { l2 = getline(&line, &line_size, fd); if (l2 > 0) { ret = parse_line(line, host, host_len, service, service_len, now, pubkey, &b64key); if (ret == 0) /* found */ { goto cleanup; } else if (ret == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) mismatch = 1; } } while(l2 >= 0); if (mismatch) ret = GNUTLS_E_CERTIFICATE_KEY_MISMATCH; else ret = GNUTLS_E_NO_CERTIFICATE_FOUND; cleanup: free(line); if (fd != NULL) fclose(fd); gnutls_free(b64key.data); return ret; }
static int do_device_source_egd (int init) { time_t now = gnutls_time (NULL); unsigned int read_size = DEVICE_READ_SIZE; if (init) { device_fd = _rndegd_connect_socket (); if (device_fd < 0) { _gnutls_debug_log ("Cannot open egd socket!\n"); return gnutls_assert_val(GNUTLS_E_FILE_ERROR); } device_last_read = now; read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */ } if ((device_fd > 0) && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL))) { /* More than 20 minutes since we last read the device */ uint8_t buf[DEVICE_READ_SIZE_MAX]; uint32_t done; for (done = 0; done < read_size;) { int res; res = _rndegd_read (&device_fd, buf + done, sizeof (buf) - done); if (res <= 0) { if (res < 0) { _gnutls_debug_log ("Failed to read egd.\n"); } else { _gnutls_debug_log ("Failed to read egd: end of file\n"); } return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); } done += res; } device_last_read = now; return yarrow256_update (&yctx, RANDOM_SOURCE_DEVICE, read_size * 8 / 2, read_size, buf); } return 0; }
static cdk_error_t literal_encode (void *data, FILE * in, FILE * out) { literal_filter_t *pfx = data; cdk_pkt_literal_t pt; cdk_stream_t si; cdk_packet_t pkt; size_t filelen; cdk_error_t rc; _cdk_log_debug ("literal filter: encode\n"); if (!pfx || !in || !out) return CDK_Inv_Value; if (!pfx->filename) { pfx->filename = cdk_strdup ("_CONSOLE"); if (!pfx->filename) return CDK_Out_Of_Core; } rc = _cdk_stream_fpopen (in, STREAMCTL_READ, &si); if (rc) return rc; filelen = strlen (pfx->filename); cdk_pkt_new (&pkt); pt = pkt->pkt.literal = cdk_calloc (1, sizeof *pt + filelen); pt->name = (char *) pt + sizeof (*pt); if (!pt) { cdk_pkt_release (pkt); cdk_stream_close (si); return CDK_Out_Of_Core; } memcpy (pt->name, pfx->filename, filelen); pt->namelen = filelen; pt->name[pt->namelen] = '\0'; pt->timestamp = (u32) gnutls_time (NULL); pt->mode = intmode_to_char (pfx->mode); pt->len = cdk_stream_get_length (si); pt->buf = si; pkt->old_ctb = 1; pkt->pkttype = CDK_PKT_LITERAL; pkt->pkt.literal = pt; rc = _cdk_pkt_write_fp (out, pkt); cdk_pkt_release (pkt); cdk_stream_close (si); return rc; }
/** * gnutls_db_check_entry: * @session: is a #gnutls_session_t structure. * @session_entry: is the session data (not key) * * Check if database entry has expired. This function is to be used * when you want to clear unnesessary session which occupy space in * your backend. * * Returns: Returns %GNUTLS_E_EXPIRED, if the database entry has * expired or 0 otherwise. **/ int gnutls_db_check_entry (gnutls_session_t session, gnutls_datum_t session_entry) { time_t timestamp; timestamp = gnutls_time (0); if (session_entry.data != NULL) if (timestamp - ((security_parameters_st *) (session_entry.data))->timestamp <= session->internals.expire_time || ((security_parameters_st *) (session_entry.data))->timestamp > timestamp || ((security_parameters_st *) (session_entry.data))->timestamp == 0) return GNUTLS_E_EXPIRED; return 0; }
static int do_device_source (int init) { time_t now = gnutls_time (NULL); int read_size = DEVICE_READ_SIZE; if (init) { int old; if (!CryptAcquireContext (&device_fd, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) { _gnutls_debug_log ("error in CryptAcquireContext!\n"); return GNUTLS_E_INTERNAL_ERROR; } device_last_read = now; read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */ } if ((device_fd != 0) && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL))) { /* More than 20 minutes since we last read the device */ uint8_t buf[DEVICE_READ_SIZE_MAX]; if (!CryptGenRandom (device_fd, (DWORD) read_size, buf)) { _gnutls_debug_log ("Error in CryptGenRandom: %s\n", GetLastError ()); return GNUTLS_E_INTERNAL_ERROR; } device_last_read = now; return yarrow256_update (&yctx, RANDOM_SOURCE_DEVICE, read_size * 8 / 2 /* we trust the system RNG */ , read_size, buf); } return 0; }
/* Read a v2 client hello. Some browsers still use that beast! * However they set their version to 3.0 or 3.1. */ int _gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data, unsigned int datalen) { uint16_t session_id_len = 0; int pos = 0; int ret = 0, sret = 0; uint16_t sizeOfSuites; gnutls_protocol_t adv_version; uint8_t rnd[GNUTLS_RANDOM_SIZE]; int len = datalen; uint16_t challenge; uint8_t session_id[GNUTLS_MAX_SESSION_ID_SIZE]; DECR_LEN(len, 2); _gnutls_handshake_log ("HSK[%p]: SSL 2.0 Hello: Client's version: %d.%d\n", session, data[pos], data[pos + 1]); set_adv_version(session, data[pos], data[pos + 1]); adv_version = _gnutls_version_get(data[pos], data[pos + 1]); ret = _gnutls_negotiate_version(session, adv_version); if (ret < 0) { gnutls_assert(); return ret; } pos += 2; /* Read uint16_t cipher_spec_length */ DECR_LEN(len, 2); sizeOfSuites = _gnutls_read_uint16(&data[pos]); pos += 2; /* read session id length */ DECR_LEN(len, 2); session_id_len = _gnutls_read_uint16(&data[pos]); pos += 2; if (session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) { gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } /* read challenge length */ DECR_LEN(len, 2); challenge = _gnutls_read_uint16(&data[pos]); pos += 2; if (challenge < 16 || challenge > GNUTLS_RANDOM_SIZE) { gnutls_assert(); return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; } /* call the user hello callback */ ret = _gnutls_user_hello_func(session, adv_version); if (ret < 0) { if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) { sret = GNUTLS_E_INT_RET_0; } else { gnutls_assert(); return ret; } } /* find an appropriate cipher suite */ DECR_LEN(len, sizeOfSuites); ret = _gnutls_handshake_select_v2_suite(session, &data[pos], sizeOfSuites); pos += sizeOfSuites; if (ret < 0) { gnutls_assert(); return ret; } /* check if the credentials (username, public key etc.) are ok */ if (_gnutls_get_kx_cred (session, _gnutls_cipher_suite_get_kx_algo(session->security_parameters. cipher_suite)) == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* set the mod_auth_st to the appropriate struct * according to the KX algorithm. This is needed since all the * handshake functions are read from there; */ session->internals.auth_struct = _gnutls_kx_auth_struct(_gnutls_cipher_suite_get_kx_algo (session->security_parameters. cipher_suite)); if (session->internals.auth_struct == NULL) { _gnutls_handshake_log ("HSK[%p]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n", session); gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } /* read random new values -skip session id for now */ DECR_LEN(len, session_id_len); /* skip session id for now */ memcpy(session_id, &data[pos], session_id_len); pos += session_id_len; DECR_LEN(len, challenge); memset(rnd, 0, GNUTLS_RANDOM_SIZE); memcpy(&rnd[GNUTLS_RANDOM_SIZE - challenge], &data[pos], challenge); ret = _gnutls_set_client_random(session, rnd); if (ret < 0) return gnutls_assert_val(ret); /* generate server random value */ ret = _gnutls_set_server_random(session, NULL); if (ret < 0) return gnutls_assert_val(ret); session->security_parameters.timestamp = gnutls_time(NULL); /* RESUME SESSION */ DECR_LEN(len, session_id_len); ret = _gnutls_server_restore_session(session, session_id, session_id_len); if (ret == 0) { /* resumed! */ /* get the new random values */ memcpy(session->internals.resumed_security_parameters. server_random, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); memcpy(session->internals.resumed_security_parameters. client_random, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); session->internals.resumed = RESUME_TRUE; return 0; } else { _gnutls_generate_session_id(session->security_parameters. session_id, &session->security_parameters. session_id_size); session->internals.resumed = RESUME_FALSE; } _gnutls_epoch_set_compression(session, EPOCH_NEXT, GNUTLS_COMP_NULL); session->security_parameters.compression_method = GNUTLS_COMP_NULL; return sret; }
int _gnutls13_recv_key_update(gnutls_session_t session, gnutls_buffer_st *buf) { int ret; time_t now = gnutls_time(0); if (buf->length != 1) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); if (unlikely(now - session->internals.last_key_update < KEY_UPDATES_PER_SEC)) { _gnutls_debug_log("reached maximum number of key updates per second (%d)\n", KEY_UPDATES_PER_SEC); return gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS); } session->internals.last_key_update = now; _gnutls_epoch_gc(session); _gnutls_handshake_log("HSK[%p]: received TLS 1.3 key update (%u)\n", session, (unsigned)buf->data[0]); switch(buf->data[0]) { case 0: /* peer updated its key, not requested our key update */ ret = update_keys(session, STAGE_UPD_PEERS); if (ret < 0) return gnutls_assert_val(ret); break; case 1: if (session->internals.hsk_flags & HSK_KEY_UPDATE_ASKED) { /* if we had asked a key update we shouldn't get this * reply */ return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); } /* peer updated its key, requested our key update */ ret = update_keys(session, STAGE_UPD_PEERS); if (ret < 0) return gnutls_assert_val(ret); /* we mark that a key update is schedule, and it * will be performed prior to sending the next application * message. */ if (session->internals.rsend_state == RECORD_SEND_NORMAL) session->internals.rsend_state = RECORD_SEND_KEY_UPDATE_1; else if (session->internals.rsend_state == RECORD_SEND_CORKED) session->internals.rsend_state = RECORD_SEND_CORKED_TO_KU; else return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); break; default: return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); } session->internals.hsk_flags &= ~(unsigned)(HSK_KEY_UPDATE_ASKED); return 0; }
/* Verify X.509 certificate chain. * * Note that the return value is an OR of GNUTLS_CERT_* elements. * * This function verifies a X.509 certificate list. The certificate * list should lead to a trusted certificate in order to be trusted. */ unsigned int _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list, int clist_size, const gnutls_x509_crt_t * trusted_cas, int tcas_size, unsigned int flags, const char *purpose, gnutls_verify_output_function func) { int i = 0, ret; unsigned int status = 0, output; time_t now = gnutls_time(0); verify_state_st vparams; if (clist_size > 1) { /* Check if the last certificate in the path is self signed. * In that case ignore it (a certificate is trusted only if it * leads to a trusted party by us, not the server's). * * This prevents from verifying self signed certificates against * themselves. This (although not bad) caused verification * failures on some root self signed certificates that use the * MD2 algorithm. */ if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1], certificate_list[clist_size - 1]) != 0) { clist_size--; } } /* We want to shorten the chain by removing the cert that matches * one of the certs we trust and all the certs after that i.e. if * cert chain is A signed-by B signed-by C signed-by D (signed-by * self-signed E but already removed above), and we trust B, remove * B, C and D. */ if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME)) i = 0; /* also replace the first one */ else i = 1; /* do not replace the first one */ for (; i < clist_size; i++) { int j; for (j = 0; j < tcas_size; j++) { /* we check for a certificate that may not be identical with the one * sent by the client, but will have the same name and key. That is * because it can happen that a CA certificate is upgraded from intermediate * CA to self-signed CA at some point. */ if (_gnutls_check_if_same_key (certificate_list[i], trusted_cas[j], i) != 0) { /* explicit time check for trusted CA that we remove from * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS */ if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) && !(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) { status |= check_time_status(trusted_cas[j], now); if (status != 0) { if (func) func(certificate_list[i], trusted_cas[j], NULL, status); return status; } } if (func) func(certificate_list[i], trusted_cas[j], NULL, status); clist_size = i; break; } } /* clist_size may have been changed which gets out of loop */ } if (clist_size == 0) { /* The certificate is already present in the trusted certificate list. * Nothing to verify. */ return status; } memset(&vparams, 0, sizeof(vparams)); vparams.now = now; vparams.max_path = MAX_VERIFY_DEPTH; vparams.func = func; ret = gnutls_x509_name_constraints_init(&vparams.nc); if (ret < 0) { gnutls_assert(); status |= GNUTLS_CERT_INVALID; return status; } ret = gnutls_x509_tlsfeatures_init(&vparams.tls_feat); if (ret < 0) { gnutls_assert(); status |= GNUTLS_CERT_INVALID; goto cleanup; } /* Verify the last certificate in the certificate path * against the trusted CA certificate list. * * If no CAs are present returns CERT_INVALID. Thus works * in self signed etc certificates. */ output = 0; ret = verify_crt(certificate_list[clist_size - 1], trusted_cas, tcas_size, flags, &output, &vparams, clist_size==1?1:0); if (ret != 1) { /* if the last certificate in the certificate * list is invalid, then the certificate is not * trusted. */ gnutls_assert(); status |= output; status |= GNUTLS_CERT_INVALID; goto cleanup; } /* Verify the certificate path (chain) */ for (i = clist_size - 1; i > 0; i--) { output = 0; if (i - 1 < 0) break; if (purpose != NULL) { ret = _gnutls_check_key_purpose(certificate_list[i], purpose, 1); if (ret != 1) { gnutls_assert(); status |= GNUTLS_CERT_INVALID; status |= GNUTLS_CERT_PURPOSE_MISMATCH; if (func) func(certificate_list[i-1], certificate_list[i], NULL, status); goto cleanup; } } /* note that here we disable this V1 CA flag. So that no version 1 * certificates can exist in a supplied chain. */ if (!(flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT)) { flags |= GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT; } if ((ret = verify_crt(certificate_list[i - 1], &certificate_list[i], 1, flags, &output, &vparams, i==1?1:0)) != 1) { gnutls_assert(); status |= output; status |= GNUTLS_CERT_INVALID; goto cleanup; } } cleanup: gnutls_x509_name_constraints_deinit(vparams.nc); gnutls_x509_tlsfeatures_deinit(vparams.tls_feat); return status; }
/** * gnutls_x509_crl_verify: * @crl: is the crl to be verified * @trusted_cas: is a certificate list that is considered to be trusted one * @tcas_size: holds the number of CA certificates in CA_list * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations. * @verify: will hold the crl verification output. * * This function will try to verify the given crl and return its verification status. * See gnutls_x509_crt_list_verify() for a detailed description of * return values. Note that since GnuTLS 3.1.4 this function includes * the time checks. * * Note that value in @verify is set only when the return value of this * function is success (i.e, failure to trust a CRL a certificate does not imply * a negative return value). * * Before GnuTLS 3.5.7 this function would return zero or a positive * number on success. * * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a * negative error value. **/ int gnutls_x509_crl_verify(gnutls_x509_crl_t crl, const gnutls_x509_crt_t * trusted_cas, unsigned tcas_size, unsigned int flags, unsigned int *verify) { /* CRL is ignored for now */ gnutls_datum_t crl_signed_data = { NULL, 0 }; gnutls_datum_t crl_signature = { NULL, 0 }; gnutls_x509_crt_t issuer = NULL; int result, hash_algo; time_t now = gnutls_time(0); unsigned int usage; if (verify) *verify = 0; if (tcas_size >= 1) issuer = find_crl_issuer(crl, trusted_cas, tcas_size); result = _gnutls_x509_get_signed_data(crl->crl, &crl->der, "tbsCertList", &crl_signed_data); if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } result = _gnutls_x509_get_signature(crl->crl, "signature", &crl_signature); if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } result = _gnutls_x509_get_signature_algorithm(crl->crl, "signatureAlgorithm.algorithm"); if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } hash_algo = gnutls_sign_get_hash_algorithm(result); /* issuer is not in trusted certificate * authorities. */ if (issuer == NULL) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; } else { if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN)) { if (gnutls_x509_crt_get_ca_status(issuer, NULL) != 1) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID; } result = gnutls_x509_crt_get_key_usage(issuer, &usage, NULL); if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; } else if (!(usage & GNUTLS_KEY_CRL_SIGN)) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE | GNUTLS_CERT_INVALID; } } } result = _gnutls_x509_verify_data(mac_to_entry(hash_algo), &crl_signed_data, &crl_signature, issuer); if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) { gnutls_assert(); /* error. ignore it */ if (verify) *verify |= GNUTLS_CERT_SIGNATURE_FAILURE; result = 0; } else if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } else if (result >= 0) { result = 0; /* everything ok */ } } { int sigalg; sigalg = gnutls_x509_crl_get_signature_algorithm(crl); if (((sigalg == GNUTLS_SIGN_RSA_MD2) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) || ((sigalg == GNUTLS_SIGN_RSA_MD5) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) { if (verify) *verify |= GNUTLS_CERT_INSECURE_ALGORITHM; result = 0; } } if (gnutls_x509_crl_get_this_update(crl) > now && verify) *verify |= GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE; if (gnutls_x509_crl_get_next_update(crl) < now && verify) *verify |= GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED; cleanup: if (verify && *verify != 0) *verify |= GNUTLS_CERT_INVALID; _gnutls_free_datum(&crl_signed_data); _gnutls_free_datum(&crl_signature); return result; }
/* Verify X.509 certificate chain using a PKCS #11 token. * * Note that the return value is an OR of GNUTLS_CERT_* elements. * * Unlike the non-PKCS#11 version, this function accepts a key purpose * (from GNUTLS_KP_...). That is because in the p11-kit trust modules * anchors are mixed and get assigned a purpose. * * This function verifies a X.509 certificate list. The certificate * list should lead to a trusted certificate in order to be trusted. */ unsigned int _gnutls_pkcs11_verify_crt_status(const char* url, const gnutls_x509_crt_t * certificate_list, unsigned clist_size, const char *purpose, unsigned int flags, gnutls_verify_output_function func) { int ret; unsigned int status = 0, i; gnutls_x509_crt_t issuer = NULL; gnutls_datum_t raw_issuer = {NULL, 0}; time_t now = gnutls_time(0); if (clist_size > 1) { /* Check if the last certificate in the path is self signed. * In that case ignore it (a certificate is trusted only if it * leads to a trusted party by us, not the server's). * * This prevents from verifying self signed certificates against * themselves. This (although not bad) caused verification * failures on some root self signed certificates that use the * MD2 algorithm. */ if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1], certificate_list[clist_size - 1]) != 0) { clist_size--; } } /* We want to shorten the chain by removing the cert that matches * one of the certs we trust and all the certs after that i.e. if * cert chain is A signed-by B signed-by C signed-by D (signed-by * self-signed E but already removed above), and we trust B, remove * B, C and D. */ if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME)) i = 0; /* also replace the first one */ else i = 1; /* do not replace the first one */ for (; i < clist_size; i++) { unsigned vflags; if (i == 0) /* in the end certificate do full comparison */ vflags = GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE| GNUTLS_PKCS11_OBJ_FLAG_COMPARE|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED; else vflags = GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE| GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED; if (gnutls_pkcs11_crt_is_known (url, certificate_list[i], vflags) != 0) { if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) && !(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) { status |= check_time_status(certificate_list[i], now); if (status != 0) { if (func) func(certificate_list[i], certificate_list[i], NULL, status); return status; } } if (func) func(certificate_list[i], certificate_list[i], NULL, status); clist_size = i; break; } /* clist_size may have been changed which gets out of loop */ } if (clist_size == 0) { /* The certificate is already present in the trusted certificate list. * Nothing to verify. */ return status; } /* check for blacklists */ for (i = 0; i < clist_size; i++) { if (gnutls_pkcs11_crt_is_known (url, certificate_list[i], GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE| GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED) != 0) { status |= GNUTLS_CERT_INVALID; status |= GNUTLS_CERT_REVOKED; if (func) func(certificate_list[i], certificate_list[i], NULL, status); goto cleanup; } } /* check against issuer */ ret = gnutls_pkcs11_get_raw_issuer(url, certificate_list[clist_size - 1], &raw_issuer, GNUTLS_X509_FMT_DER, GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT|GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE); if (ret < 0) { gnutls_assert(); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && clist_size > 2) { /* check if the last certificate in the chain is present * in our trusted list, and if yes, verify against it. */ ret = gnutls_pkcs11_crt_is_known(url, certificate_list[clist_size - 1], GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED|GNUTLS_PKCS11_OBJ_FLAG_COMPARE); if (ret != 0) { return _gnutls_verify_crt_status(certificate_list, clist_size, &certificate_list[clist_size - 1], 1, flags, purpose, func); } } status |= GNUTLS_CERT_INVALID; status |= GNUTLS_CERT_SIGNER_NOT_FOUND; /* verify the certificate list against 0 trusted CAs in order * to get, any additional flags from the certificate list (e.g., * insecure algorithms or expired */ status |= _gnutls_verify_crt_status(certificate_list, clist_size, NULL, 0, flags, purpose, func); goto cleanup; } ret = gnutls_x509_crt_init(&issuer); if (ret < 0) { gnutls_assert(); status |= GNUTLS_CERT_INVALID; status |= GNUTLS_CERT_SIGNER_NOT_FOUND; goto cleanup; } ret = gnutls_x509_crt_import(issuer, &raw_issuer, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert(); status |= GNUTLS_CERT_INVALID; status |= GNUTLS_CERT_SIGNER_NOT_FOUND; goto cleanup; } /* check if the raw issuer is blacklisted (it can happen if * the issuer is both in the trusted list and the blacklisted) */ if (gnutls_pkcs11_crt_is_known (url, issuer, GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE| GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED) != 0) { status |= GNUTLS_CERT_INVALID; status |= GNUTLS_CERT_SIGNER_NOT_FOUND; /* if the signer is revoked - it is as if it doesn't exist */ goto cleanup; } /* security modules that provide trust, bundle all certificates (of all purposes) * together. In software that doesn't specify any purpose assume the default to * be www-server. */ ret = _gnutls_check_key_purpose(issuer, purpose==NULL?GNUTLS_KP_TLS_WWW_SERVER:purpose, 0); if (ret != 1) { gnutls_assert(); status |= GNUTLS_CERT_INVALID; status |= GNUTLS_CERT_SIGNER_NOT_FOUND; goto cleanup; } status = _gnutls_verify_crt_status(certificate_list, clist_size, &issuer, 1, flags, purpose, func); cleanup: gnutls_free(raw_issuer.data); if (issuer != NULL) gnutls_x509_crt_deinit(issuer); return status; }
static int append_status_request(void *_ctx, gnutls_buffer_st *buf) { struct ocsp_req_ctx_st *ctx = _ctx; gnutls_session_t session = ctx->session; int ret; gnutls_datum_t resp; unsigned free_resp = 0; assert(session->internals.selected_ocsp_func != NULL || session->internals.selected_ocsp_length != 0); /* The global ocsp callback function can only be used to return * a single certificate request */ if (session->internals.selected_ocsp_length == 1 && ctx->cert_index != 0) return 0; if (session->internals.selected_ocsp_length > 0) { if (ctx->cert_index < session->internals.selected_ocsp_length) { if ((session->internals.selected_ocsp[ctx->cert_index].exptime != 0 && gnutls_time(0) >= session->internals.selected_ocsp[ctx->cert_index].exptime) || session->internals.selected_ocsp[ctx->cert_index].response.data == NULL) { return 0; } resp.data = session->internals.selected_ocsp[ctx->cert_index].response.data; resp.size = session->internals.selected_ocsp[ctx->cert_index].response.size; ret = 0; } else { return 0; } } else if (session->internals.selected_ocsp_func) { if (ctx->cert_index == 0) { ret = session->internals.selected_ocsp_func(session, session->internals.selected_ocsp_func_ptr, &resp); free_resp = 1; } else { return 0; } } else return 0; if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS || resp.data == 0) { return 0; } else if (ret < 0) { return gnutls_assert_val(ret); } ret = _gnutls_buffer_append_data(buf, "\x01", 1); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_buffer_append_data_prefix(buf, 24, resp.data, resp.size); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = 0; cleanup: if (free_resp) gnutls_free(resp.data); return ret; }
static int encrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, struct ticket_st *ticket) { cipher_hd_st cipher_hd; gnutls_datum_t key, IV; gnutls_datum_t state = {NULL,0}, encrypted_state = {NULL,0}; uint8_t iv[IV_SIZE]; gnutls_datum_t mac_secret; uint32_t t; int ret; /* Pack security parameters. */ ret = _gnutls_session_pack(session, &state); if (ret < 0) { gnutls_assert(); return ret; } encrypted_state.size = ((state.size + BLOCK_SIZE - 1) / BLOCK_SIZE) * BLOCK_SIZE; encrypted_state.data = gnutls_calloc(1, encrypted_state.size); if (!encrypted_state.data) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } memcpy(encrypted_state.data, state.data, state.size); /* Encrypt state */ key.data = (void *) &priv->key[KEY_POS]; key.size = CIPHER_KEY_SIZE; IV.data = iv; IV.size = IV_SIZE; t = gnutls_time(0); memcpy(iv, &t, 4); ret = gnutls_rnd(GNUTLS_RND_NONCE, iv+4, IV_SIZE-4); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(CIPHER), &key, &IV, 1); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data, encrypted_state.size); if (ret < 0) { gnutls_assert(); goto cleanup2; } /* Fill the ticket structure to compute MAC. */ memcpy(ticket->key_name, &priv->key[NAME_POS], KEY_NAME_SIZE); memcpy(ticket->IV, IV.data, IV.size); ticket->encrypted_state_len = encrypted_state.size; ticket->encrypted_state = encrypted_state.data; mac_secret.data = &priv->key[MAC_SECRET_POS]; mac_secret.size = MAC_SECRET_SIZE; ret = digest_ticket(&mac_secret, ticket, ticket->mac); if (ret < 0) { gnutls_assert(); goto cleanup2; } encrypted_state.data = NULL; ret = 0; cleanup2: _gnutls_cipher_deinit(&cipher_hd); cleanup: _gnutls_free_datum(&state); _gnutls_free_datum(&encrypted_state); return ret; }
/* This will receive record layer packets and add them to * application_data_buffer and handshake_data_buffer. * * If the htype is not -1 then handshake timeouts * will be enforced. */ ssize_t _gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type, gnutls_handshake_description_t htype) { uint64 *packet_sequence; uint8_t *ciphertext; mbuffer_st* bufel = NULL, *decrypted = NULL; int ret; int empty_packet = 0; record_parameters_st *record_params; record_state_st *record_state; struct tls_record_st record; time_t now, tleft = 0; begin: if (empty_packet > MAX_EMPTY_PACKETS_SEQUENCE) { gnutls_assert (); return GNUTLS_E_TOO_MANY_EMPTY_PACKETS; } memset(&record, 0, sizeof(record)); if (session->internals.read_eof != 0) { /* if we have already read an EOF */ return 0; } else if (session_is_valid (session) != 0 || session->internals.may_not_read != 0) return gnutls_assert_val(GNUTLS_E_INVALID_SESSION); /* get the record state parameters */ ret = _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &record_params); if (ret < 0) return gnutls_assert_val (ret); /* Safeguard against processing data with an incomplete cipher state. */ if (!record_params->initialized) return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR); record_state = &record_params->read; if (htype != (unsigned)-1 && session->internals.handshake_endtime > 0) { now = gnutls_time(0); if (now < session->internals.handshake_endtime) tleft = (session->internals.handshake_endtime - now) * 1000; else return gnutls_assert_val(GNUTLS_E_TIMEDOUT); } /* receive headers */ ret = recv_headers(session, type, htype, &record, tleft); if (ret < 0) { ret = gnutls_assert_val_fatal(ret); goto recv_error; } if (IS_DTLS(session)) packet_sequence = &record.sequence; else packet_sequence = &record_state->sequence_number; if (htype != (unsigned)-1 && session->internals.handshake_endtime > 0) { now = gnutls_time(0); if (now < session->internals.handshake_endtime) tleft = (session->internals.handshake_endtime - now) * 1000; else return gnutls_assert_val(GNUTLS_E_TIMEDOUT); } /* Read the packet data and insert it to record_recv_buffer. */ ret = _gnutls_io_read_buffered (session, record.packet_size, record.type, tleft); if (ret != record.packet_size) { gnutls_assert(); goto recv_error; } /* ok now we are sure that we have read all the data - so * move on ! */ ret = _mbuffer_linearize (&session->internals.record_recv_buffer); if (ret < 0) return gnutls_assert_val(ret); bufel = _mbuffer_head_get_first (&session->internals.record_recv_buffer, NULL); if (bufel == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); /* We allocate the maximum possible to allow few compressed bytes to expand to a * full record. */ decrypted = _mbuffer_alloc(MAX_RECORD_RECV_SIZE(session), MAX_RECORD_RECV_SIZE(session)); if (decrypted == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ciphertext = (uint8_t*)_mbuffer_get_udata_ptr(bufel) + record.header_size; /* decrypt the data we got. */ ret = _gnutls_decrypt (session, ciphertext, record.length, _mbuffer_get_udata_ptr(decrypted), _mbuffer_get_udata_size(decrypted), record.type, record_params, packet_sequence); if (ret >= 0) _mbuffer_set_udata_size(decrypted, ret); _mbuffer_head_remove_bytes (&session->internals.record_recv_buffer, record.header_size + record.length); if (ret < 0) { gnutls_assert(); _gnutls_audit_log(session, "Discarded message[%u] due to invalid decryption\n", (unsigned int)_gnutls_uint64touint32 (packet_sequence)); goto sanity_check_error; } /* check for duplicates. We check after the message * is processed and authenticated to avoid someone * messing with our windows. */ if (IS_DTLS(session)) { ret = _dtls_record_check(record_params, packet_sequence); if (ret < 0) { _gnutls_audit_log(session, "Discarded duplicate message[%u]: %s\n", (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type)); goto sanity_check_error; } _gnutls_record_log ("REC[%p]: Decrypted Packet[%u.%u] %s(%d) with length: %d\n", session, (unsigned int)record.sequence.i[0]*256 +(unsigned int)record.sequence.i[1], (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted)); } else { _gnutls_record_log ("REC[%p]: Decrypted Packet[%u] %s(%d) with length: %d\n", session, (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted)); } /* increase sequence number */ if (!IS_DTLS(session) && sequence_increment (session, &record_state->sequence_number) != 0) { session_invalidate (session); gnutls_assert (); ret = GNUTLS_E_RECORD_LIMIT_REACHED; goto sanity_check_error; } /* (originally for) TLS 1.0 CBC protection. * Actually this code is called if we just received * an empty packet. An empty TLS packet is usually * sent to protect some vulnerabilities in the CBC mode. * In that case we go to the beginning and start reading * the next packet. */ if (_mbuffer_get_udata_size(decrypted) == 0) { _mbuffer_xfree(&decrypted); empty_packet++; goto begin; } if (record.v2) decrypted->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2; else { uint8_t * p = _mbuffer_get_udata_ptr(decrypted); decrypted->htype = p[0]; } ret = record_add_to_buffers (session, &record, type, htype, packet_sequence, decrypted); /* bufel is now either deinitialized or buffered somewhere else */ if (ret < 0) return gnutls_assert_val(ret); return ret; discard: session->internals.dtls.packets_dropped++; /* discard the whole received fragment. */ bufel = _mbuffer_head_pop_first(&session->internals.record_recv_buffer); _mbuffer_xfree(&bufel); return gnutls_assert_val(GNUTLS_E_AGAIN); sanity_check_error: if (IS_DTLS(session)) { session->internals.dtls.packets_dropped++; ret = gnutls_assert_val(GNUTLS_E_AGAIN); goto cleanup; } session_unresumable (session); session_invalidate (session); cleanup: _mbuffer_xfree(&decrypted); return ret; recv_error: if (ret < 0 && gnutls_error_is_fatal (ret) == 0) return ret; if (IS_DTLS(session)) { goto discard; } session_invalidate (session); if (type == GNUTLS_ALERT) /* we were expecting close notify */ { gnutls_assert (); return 0; } session_unresumable (session); if (ret == 0) return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; else return ret; }
static int do_device_source_urandom (int init) { time_t now = gnutls_time (NULL); unsigned int read_size = DEVICE_READ_SIZE; if (init) { int old; device_fd = open ("/dev/urandom", O_RDONLY); if (device_fd < 0) { _gnutls_debug_log ("Cannot open urandom!\n"); return GNUTLS_E_FILE_ERROR; } old = fcntl (device_fd, F_GETFD); fcntl (device_fd, F_SETFD, old | 1); device_last_read = now; read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */ } if ((device_fd > 0) && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL))) { /* More than 20 minutes since we last read the device */ uint8_t buf[DEVICE_READ_SIZE_MAX]; uint32_t done; for (done = 0; done < read_size;) { int res; do res = read (device_fd, buf + done, sizeof (buf) - done); while (res < 0 && errno == EINTR); if (res <= 0) { if (res < 0) { _gnutls_debug_log ("Failed to read /dev/urandom: %s\n", strerror (errno)); } else { _gnutls_debug_log ("Failed to read /dev/urandom: end of file\n"); } return GNUTLS_E_INTERNAL_ERROR; } done += res; } device_last_read = now; return yarrow256_update (&yctx, RANDOM_SOURCE_DEVICE, read_size * 8 / 2 /* we trust the RNG */ , read_size, buf); } return 0; }
static int wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize) { struct generators_ctx_st *ctx = _ctx; struct prng_ctx_st *prng_ctx; int ret, reseed = 0; uint8_t new_key[PRNG_KEY_SIZE]; time_t now; if (level == GNUTLS_RND_RANDOM || level == GNUTLS_RND_KEY) prng_ctx = &ctx->normal; else if (level == GNUTLS_RND_NONCE) prng_ctx = &ctx->nonce; else return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED); /* Two reasons for this memset(): * 1. avoid getting filled with valgrind warnings * 2. avoid a cipher/PRNG failure to expose stack data */ memset(data, 0, datasize); now = gnutls_time(0); /* We re-seed based on time in addition to output data. That is, * to prevent a temporal state compromise to become permanent for low * traffic sites */ if (unlikely(_gnutls_detect_fork(prng_ctx->forkid))) { reseed = 1; } else { if (now > prng_ctx->last_reseed + prng_reseed_time[level]) reseed = 1; } if (reseed != 0 || prng_ctx->counter > prng_reseed_limits[level]) { if (level == GNUTLS_RND_NONCE) { ret = wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, new_key, sizeof(new_key)); } else { /* we also use the system entropy to reduce the impact * of a temporal state compromise for these two levels. */ ret = _rnd_get_system_entropy(new_key, sizeof(new_key)); } if (ret < 0) { gnutls_assert(); goto cleanup; } ret = single_prng_init(prng_ctx, new_key, sizeof(new_key), 0); if (ret < 0) { gnutls_assert(); goto cleanup; } prng_ctx->last_reseed = now; prng_ctx->forkid = _gnutls_get_forkid(); } chacha_crypt(&prng_ctx->ctx, datasize, data, data); prng_ctx->counter += datasize; if (level == GNUTLS_RND_KEY) { /* prevent backtracking */ ret = wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, new_key, sizeof(new_key)); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = single_prng_init(prng_ctx, new_key, sizeof(new_key), 0); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = 0; cleanup: return ret; }
/* Verify X.509 certificate chain. * * Note that the return value is an OR of GNUTLS_CERT_* elements. * * This function verifies a X.509 certificate list. The certificate * list should lead to a trusted certificate in order to be trusted. */ unsigned int _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list, int clist_size, const gnutls_x509_crt_t * trusted_cas, int tcas_size, unsigned int flags, gnutls_verify_output_function func) { int i = 0, ret; unsigned int status = 0, output; time_t now = gnutls_time (0); gnutls_x509_crt_t issuer = NULL; if (clist_size > 1) { /* Check if the last certificate in the path is self signed. * In that case ignore it (a certificate is trusted only if it * leads to a trusted party by us, not the server's). * * This prevents from verifying self signed certificates against * themselves. This (although not bad) caused verification * failures on some root self signed certificates that use the * MD2 algorithm. */ if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1], certificate_list[clist_size - 1]) > 0) { clist_size--; } } /* We want to shorten the chain by removing the cert that matches * one of the certs we trust and all the certs after that i.e. if * cert chain is A signed-by B signed-by C signed-by D (signed-by * self-signed E but already removed above), and we trust B, remove * B, C and D. */ if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME)) i = 0; /* also replace the first one */ else i = 1; /* do not replace the first one */ for (; i < clist_size; i++) { int j; for (j = 0; j < tcas_size; j++) { if (check_if_same_cert (certificate_list[i], trusted_cas[j]) == 0) { /* explicity time check for trusted CA that we remove from * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS */ if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) && !(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) { status |= check_time (trusted_cas[j], now); if (status != 0) { if (func) func(certificate_list[i], trusted_cas[j], NULL, status); return status; } } if (func) func(certificate_list[i], trusted_cas[j], NULL, status); clist_size = i; break; } } /* clist_size may have been changed which gets out of loop */ } if (clist_size == 0) { /* The certificate is already present in the trusted certificate list. * Nothing to verify. */ return status; } /* Verify the last certificate in the certificate path * against the trusted CA certificate list. * * If no CAs are present returns CERT_INVALID. Thus works * in self signed etc certificates. */ output = 0; ret = _gnutls_verify_certificate2 (certificate_list[clist_size - 1], trusted_cas, tcas_size, flags, &output, &issuer, now, func); if (ret == 0) { /* if the last certificate in the certificate * list is invalid, then the certificate is not * trusted. */ gnutls_assert (); status |= output; status |= GNUTLS_CERT_INVALID; return status; } /* Verify the certificate path (chain) */ for (i = clist_size - 1; i > 0; i--) { output = 0; if (i - 1 < 0) break; /* note that here we disable this V1 CA flag. So that no version 1 * certificates can exist in a supplied chain. */ if (!(flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT)) flags &= ~(GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); if ((ret = _gnutls_verify_certificate2 (certificate_list[i - 1], &certificate_list[i], 1, flags, &output, NULL, now, func)) == 0) { status |= output; status |= GNUTLS_CERT_INVALID; return status; } } return 0; }
static int decrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, struct ticket_st *ticket) { cipher_hd_st cipher_hd; gnutls_datum_t key, IV, state, mac_secret; uint8_t cmac[MAC_SIZE]; time_t timestamp = gnutls_time(0); int ret; /* Check the integrity of ticket */ mac_secret.data = (void *) &priv->key[MAC_SECRET_POS]; mac_secret.size = MAC_SECRET_SIZE; ret = digest_ticket(&mac_secret, ticket, cmac); if (ret < 0) return gnutls_assert_val(ret); if (memcmp(ticket->mac, cmac, MAC_SIZE)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (ticket->encrypted_state_len % BLOCK_SIZE != 0) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); /* Decrypt encrypted_state */ key.data = (void *) &priv->key[KEY_POS]; key.size = CIPHER_KEY_SIZE; IV.data = ticket->IV; IV.size = IV_SIZE; ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(CIPHER), &key, &IV, 0); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_cipher_decrypt(&cipher_hd, ticket->encrypted_state, ticket->encrypted_state_len); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Unpack security parameters. */ state.data = ticket->encrypted_state; state.size = ticket->encrypted_state_len; ret = _gnutls_session_unpack(session, &state); if (ret < 0) { gnutls_assert(); goto cleanup; } if (timestamp - session->internals.resumed_security_parameters.timestamp > session->internals.expire_time || session->internals.resumed_security_parameters.timestamp > timestamp) { gnutls_assert(); ret = GNUTLS_E_EXPIRED; goto cleanup; } ret = _gnutls_check_resumed_params(session); if (ret < 0) { gnutls_assert(); goto cleanup; } session->internals.resumed = RESUME_TRUE; ret = 0; cleanup: _gnutls_cipher_deinit(&cipher_hd); return ret; }