int ss_check_hash(buffer_t *buf, chunk_t *chunk, enc_ctx_t *ctx, size_t capacity) { int i, j, k; ssize_t blen = buf->len; uint32_t cidx = chunk->idx; brealloc(chunk->buf, chunk->len + blen, capacity); brealloc(buf, chunk->len + blen, capacity); for (i = 0, j = 0, k = 0; i < blen; i++) { chunk->buf->array[cidx++] = buf->array[k++]; if (cidx == CLEN_BYTES) { uint16_t clen = ntohs(*((uint16_t *)chunk->buf->array)); brealloc(chunk->buf, clen + AUTH_BYTES, capacity); chunk->len = clen; } if (cidx == chunk->len + AUTH_BYTES) { // Compare hash uint8_t hash[ONETIMEAUTH_BYTES * 2]; uint8_t key[MAX_IV_LENGTH + sizeof(uint32_t)]; uint32_t c = htonl(chunk->counter); memcpy(key, ctx->evp.iv, enc_iv_len); memcpy(key + enc_iv_len, &c, sizeof(uint32_t)); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), key, enc_iv_len + sizeof(uint32_t), (uint8_t *)chunk->buf->array + AUTH_BYTES, chunk->len, hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), key, enc_iv_len + sizeof(uint32_t), (uint8_t *)chunk->buf->array + AUTH_BYTES, chunk->len, hash); #else sha1_hmac(key, enc_iv_len + sizeof(uint32_t), (uint8_t *)chunk->buf->array + AUTH_BYTES, chunk->len, hash); #endif if (safe_memcmp(hash, chunk->buf->array + CLEN_BYTES, ONETIMEAUTH_BYTES) != 0) { return 0; } // Copy chunk back to buffer memmove(buf->array + j + chunk->len, buf->array + k, blen - i - 1); memcpy(buf->array + j, chunk->buf->array + AUTH_BYTES, chunk->len); // Reset the base offset j += chunk->len; k = j; cidx = 0; chunk->counter++; } } buf->len = j; chunk->idx = cidx; return 1; }
NOEXPORT ALLOC_LIST *get_alloc_list_ptr(void *ptr, const char *file, int line) { ALLOC_LIST *alloc_list; if(!tls_initialized) fatal_debug("str not initialized", file, line); alloc_list=(ALLOC_LIST *)ptr-1; if(alloc_list->magic!=0xa110c8ed) /* not allocated by str_alloc() */ fatal_debug("Bad magic", file, line); /* LOL */ if(alloc_list->tls /* not detached */ && alloc_list->tls!=tls_get()) fatal_debug("Memory allocated in a different thread", file, line); if(alloc_list->valid_canary!=0xabadbabe && safe_memcmp((uint8_t *)ptr+alloc_list->size, canary, sizeof canary)) fatal_debug("Dead canary", file, line); /* LOL */ return alloc_list; }
NOEXPORT int compare_pubkeys(X509 *c1, X509 *c2) { #if OPENSSL_VERSION_NUMBER>=0x0090700fL ASN1_BIT_STRING *k1=X509_get0_pubkey_bitstr(c1); ASN1_BIT_STRING *k2=X509_get0_pubkey_bitstr(c2); if(!k1 || !k2 || k1->length!=k2->length || k1->length<0 || safe_memcmp(k1->data, k2->data, (size_t)k1->length)) { s_log(LOG_DEBUG, "CERT: Public keys do not match"); return 0; /* reject */ } #else (void)c1; /* skip warning about unused parameter */ (void)c2; /* skip warning about unused parameter */ #endif s_log(LOG_INFO, "CERT: Locally installed certificate matched"); return 1; /* accept */ }
int ss_onetimeauth_verify(buffer_t *buf, uint8_t *iv) { uint8_t hash[ONETIMEAUTH_BYTES * 2]; uint8_t auth_key[MAX_IV_LENGTH + MAX_KEY_LENGTH]; memcpy(auth_key, iv, enc_iv_len); memcpy(auth_key + enc_iv_len, enc_key, enc_key_len); size_t len = buf->len - ONETIMEAUTH_BYTES; #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, len, hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, len, hash); #else sha1_hmac(auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, len, hash); #endif return safe_memcmp(buf->array + len, hash, ONETIMEAUTH_BYTES); }
NOEXPORT void cache_transfer(SSL_CTX *ctx, const u_char type, const long timeout, const u_char *key, const size_t key_len, const u_char *val, const size_t val_len, unsigned char **ret, size_t *ret_len) { char session_id_txt[2*SSL_MAX_SSL_SESSION_ID_LENGTH+1]; const char hex[16]="0123456789ABCDEF"; const char *type_description[]={"new", "get", "remove"}; unsigned i; SOCKET s; ssize_t len; struct timeval t; CACHE_PACKET *packet; SERVICE_OPTIONS *section; if(ret) /* set error as the default result if required */ *ret=NULL; /* log the request information */ for(i=0; i<key_len && i<SSL_MAX_SSL_SESSION_ID_LENGTH; ++i) { session_id_txt[2*i]=hex[key[i]>>4]; session_id_txt[2*i+1]=hex[key[i]&0x0f]; } session_id_txt[2*i]='\0'; s_log(LOG_INFO, "cache_transfer: request=%s, timeout=%ld, id=%s, length=%lu", type_description[type], timeout, session_id_txt, (long unsigned)val_len); /* allocate UDP packet buffer */ if(key_len>SSL_MAX_SSL_SESSION_ID_LENGTH) { s_log(LOG_ERR, "cache_transfer: session id too big (%lu bytes)", (unsigned long)key_len); return; } if(val_len>MAX_VAL_LEN) { s_log(LOG_ERR, "cache_transfer: encoded session too big (%lu bytes)", (unsigned long)key_len); return; } packet=str_alloc(sizeof(CACHE_PACKET)); /* setup packet */ packet->version=1; packet->type=type; packet->timeout=htons((u_short)(timeout<64800?timeout:64800));/* 18 hours */ memcpy(packet->key, key, key_len); memcpy(packet->val, val, val_len); /* create the socket */ s=s_socket(AF_INET, SOCK_DGRAM, 0, 0, "cache_transfer: socket"); if(s==INVALID_SOCKET) { str_free(packet); return; } /* retrieve pointer to the section structure of this ctx */ section=SSL_CTX_get_ex_data(ctx, index_opt); if(sendto(s, (void *)packet, #ifdef USE_WIN32 (int) #endif (sizeof(CACHE_PACKET)-MAX_VAL_LEN+val_len), 0, §ion->sessiond_addr.sa, addr_len(§ion->sessiond_addr))<0) { sockerror("cache_transfer: sendto"); closesocket(s); str_free(packet); return; } if(!ret || !ret_len) { /* no response is required */ closesocket(s); str_free(packet); return; } /* set recvfrom timeout to 200ms */ t.tv_sec=0; t.tv_usec=200; if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&t, sizeof t)<0) { sockerror("cache_transfer: setsockopt SO_RCVTIMEO"); closesocket(s); str_free(packet); return; } /* retrieve response */ len=recv(s, (void *)packet, sizeof(CACHE_PACKET), 0); closesocket(s); if(len<0) { if(get_last_socket_error()==S_EWOULDBLOCK || get_last_socket_error()==S_EAGAIN) s_log(LOG_INFO, "cache_transfer: recv timeout"); else sockerror("cache_transfer: recv"); str_free(packet); return; } /* parse results */ if(len<(int)sizeof(CACHE_PACKET)-MAX_VAL_LEN || /* too short */ packet->version!=1 || /* wrong version */ safe_memcmp(packet->key, key, key_len)) { /* wrong session id */ s_log(LOG_DEBUG, "cache_transfer: malformed packet received"); str_free(packet); return; } if(packet->type!=CACHE_RESP_OK) { s_log(LOG_INFO, "cache_transfer: session not found"); str_free(packet); return; } *ret_len=(size_t)len-(sizeof(CACHE_PACKET)-MAX_VAL_LEN); *ret=str_alloc(*ret_len); s_log(LOG_INFO, "cache_transfer: session found"); memcpy(*ret, packet->val, *ret_len); str_free(packet); }
static int server_recv_params(gnutls_session_t session, const unsigned char *data, size_t len, const gnutls_psk_server_credentials_t pskcred) { int ret; const mac_entry_st *prf; gnutls_datum_t full_client_hello; uint8_t binder_value[MAX_HASH_SIZE]; uint16_t psk_index, i; gnutls_datum_t binder_recvd = { NULL, 0 }; gnutls_datum_t key = {NULL, 0}; psk_ext_parser_st psk_parser; psk_ext_iter_st psk_iter; struct psk_st psk; psk_auth_info_t info; tls13_ticket_st ticket_data; /* These values should be set properly when session ticket is accepted. */ uint32_t ticket_age = UINT32_MAX; struct timespec ticket_creation_time = { 0, 0 }; bool resuming; ret = _gnutls13_psk_ext_parser_init(&psk_parser, data, len); if (ret < 0) { /* No PSKs advertised by client */ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) return 0; return gnutls_assert_val(ret); } _gnutls13_psk_ext_iter_init(&psk_iter, &psk_parser); for (psk_index = 0; ; psk_index++) { ret = _gnutls13_psk_ext_iter_next_identity(&psk_iter, &psk); if (ret < 0) { /* We couldn't find any usable PSK */ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) return 0; return gnutls_assert_val(ret); } /* This will unpack the session ticket if it is well * formed and has the expected name */ if (!(session->internals.flags & GNUTLS_NO_TICKETS) && (ret = _gnutls13_unpack_session_ticket(session, &psk.identity, &ticket_data)) == 0) { prf = ticket_data.prf; session->internals.resumption_requested = 1; /* Check whether ticket is stale or not */ ticket_age = psk.ob_ticket_age - ticket_data.age_add; if (ticket_age / 1000 > ticket_data.lifetime) { gnutls_assert(); tls13_ticket_deinit(&ticket_data); continue; } ret = compute_psk_from_ticket(&ticket_data, &key); if (ret < 0) { gnutls_assert(); tls13_ticket_deinit(&ticket_data); continue; } memcpy(&ticket_creation_time, &ticket_data.creation_time, sizeof(struct timespec)); tls13_ticket_deinit(&ticket_data); resuming = 1; break; } else if (pskcred && psk.ob_ticket_age == 0 && psk.identity.size > 0 && psk.identity.size <= MAX_USERNAME_SIZE) { /* _gnutls_psk_pwd_find_entry() expects 0-terminated identities */ char identity_str[MAX_USERNAME_SIZE + 1]; prf = pskcred->binder_algo; memcpy(identity_str, psk.identity.data, psk.identity.size); identity_str[psk.identity.size] = 0; /* this fails only on configuration errors; as such we always * return its error code in that case */ ret = _gnutls_psk_pwd_find_entry(session, identity_str, &key); if (ret < 0) return gnutls_assert_val(ret); resuming = 0; break; } } _gnutls13_psk_ext_iter_init(&psk_iter, &psk_parser); for (i = 0; i <= psk_index; i++) { ret = _gnutls13_psk_ext_iter_next_binder(&psk_iter, &binder_recvd); if (ret < 0) { gnutls_assert(); /* We couldn't extract binder */ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto fail; } } /* Get full ClientHello */ if (!_gnutls_ext_get_full_client_hello(session, &full_client_hello)) { ret = GNUTLS_E_INTERNAL_ERROR; gnutls_assert(); goto fail; } /* Compute the binder value for this PSK */ ret = compute_psk_binder(session, prf, psk_parser.binders_len+2, 0, 0, &key, &full_client_hello, resuming, binder_value); if (ret < 0) { gnutls_assert(); goto fail; } if (_gnutls_mac_get_algo_len(prf) != binder_recvd.size || safe_memcmp(binder_value, binder_recvd.data, binder_recvd.size)) { gnutls_assert(); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto fail; } if (session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK) _gnutls_handshake_log("EXT[%p]: selected DHE-PSK mode\n", session); else { reset_cand_groups(session); _gnutls_handshake_log("EXT[%p]: selected PSK mode\n", session); } /* save the username in psk_auth_info to make it available * using gnutls_psk_server_get_username() */ if (!resuming) { assert(psk.identity.size < sizeof(info->username)); ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1); if (ret < 0) { gnutls_assert(); goto fail; } info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); assert(info != NULL); memcpy(info->username, psk.identity.data, psk.identity.size); info->username[psk.identity.size] = 0; _gnutls_handshake_log("EXT[%p]: selected PSK identity: %s (%d)\n", session, info->username, psk_index); } else { if (session->internals.hsk_flags & HSK_EARLY_DATA_ACCEPTED) { if (session->internals.anti_replay) { ret = _gnutls_anti_replay_check(session->internals.anti_replay, ticket_age, &ticket_creation_time, &binder_recvd); if (ret < 0) { session->internals.hsk_flags &= ~HSK_EARLY_DATA_ACCEPTED; _gnutls_handshake_log("EXT[%p]: replay detected; rejecting early data\n", session); } } else { _gnutls_handshake_log("EXT[%p]: anti-replay is not enabled; rejecting early data\n", session); session->internals.hsk_flags &= ~HSK_EARLY_DATA_ACCEPTED; } } session->internals.resumed = RESUME_TRUE; _gnutls_handshake_log("EXT[%p]: selected resumption PSK identity (%d)\n", session, psk_index); } session->internals.hsk_flags |= HSK_PSK_SELECTED; /* Reference the selected pre-shared key */ session->key.binders[0].psk.data = key.data; session->key.binders[0].psk.size = key.size; session->key.binders[0].idx = psk_index; session->key.binders[0].prf = prf; session->key.binders[0].resumption = resuming; ret = _gnutls_generate_early_secrets_for_psk(session); if (ret < 0) { gnutls_assert(); goto fail; } return 0; fail: gnutls_free(key.data); return ret; }