void doit (void) { char digest[20]; int err; /* XXX: We need this to fix secure memory. */ gnutls_global_init (); err = _gnutls_hmac_fast (GNUTLS_MAC_MD5, "keykeykey", 9, "abcdefgh", 8, digest); if (err < 0) fail ("_gnutls_hmac_fast(MD5) failed: %d\n", err); else { if (memcmp (digest, "\x3c\xb0\x9d\x83\x28\x01\xef\xc0" "\x7b\xb3\xaf\x42\x69\xe5\x93\x9a", 16) == 0) success ("_gnutls_hmac_fast(MD5) OK\n"); else { hexprint (digest, 16); fail ("_gnutls_hmac_fast(MD5) failure\n"); } } err = _gnutls_hmac_fast (GNUTLS_MAC_SHA1, "keykeykey", 9, "abcdefgh", 8, digest); if (err < 0) fail ("_gnutls_hmac_fast(SHA1) failed: %d\n", err); else { if (memcmp (digest, "\x58\x93\x7a\x58\xfe\xea\x82\xf8" "\x0e\x64\x62\x01\x40\x2b\x2c\xed\x5d\x54\xc1\xfa", 20) == 0) success ("_gnutls_hmac_fast(SHA1) OK\n"); else { hexprint (digest, 20); fail ("_gnutls_hmac_fast(SHA1) failure\n"); } } err = _gnutls_pbkdf2_sha1 ("password", 8, "salt", 4, 4711, digest, 16); if (err < 0) fail ("_gnutls_pkcs5_pbkdf2_sha1() failed: %d\n", err); else { if (memcmp (digest, "\x09\xb7\x85\x57\xdd\xf6\x07\x15" "\x1c\x52\x34\xde\xba\x5c\xdc\x59", 16) == 0) success ("_gnutls_pkcs5_pbkdf2_sha1() OK\n"); else { hexprint (digest, 16); fail ("_gnutls_pkcs5_pbkdf2_sha1() failure\n"); } } gnutls_global_deinit (); }
/** * gnutls_dtls_cookie_verify: * @key: is a random key to be used at cookie generation * @client_data: contains data identifying the client (i.e. address) * @client_data_size: The size of client's data * @_msg: An incoming message that initiates a connection. * @msg_size: The size of the message. * @prestate: The cookie of this client. * * This function will verify an incoming message for * a valid cookie. If a valid cookie is returned then * it should be associated with the session using * gnutls_dtls_prestate_set(); * * Returns: %GNUTLS_E_SUCCESS (0) on success, or a negative error code. * * Since: 3.0 **/ int gnutls_dtls_cookie_verify(gnutls_datum_t* key, void* client_data, size_t client_data_size, void* _msg, size_t msg_size, gnutls_dtls_prestate_st* prestate) { gnutls_datum_t cookie; int ret; unsigned int pos, sid_size; uint8_t * msg = _msg; uint8_t digest[C_HASH_SIZE]; if (key == NULL || key->data == NULL || key->size == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); /* format: * version - 2 bytes * random - 32 bytes * session_id - 1 byte length + content * cookie - 1 byte length + content */ pos = 34+DTLS_RECORD_HEADER_SIZE+DTLS_HANDSHAKE_HEADER_SIZE; if (msg_size < pos+1) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); sid_size = msg[pos++]; if (sid_size > 32 || msg_size < pos+sid_size+1) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); pos += sid_size; cookie.size = msg[pos++]; if (msg_size < pos+cookie.size+1) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); cookie.data = &msg[pos]; if (cookie.size != COOKIE_SIZE) { if (cookie.size > 0) _gnutls_audit_log(NULL, "Received cookie with illegal size %d. Expected %d\n", (int)cookie.size, COOKIE_SIZE); return gnutls_assert_val(GNUTLS_E_BAD_COOKIE); } ret = _gnutls_hmac_fast(C_HASH, key->data, key->size, client_data, client_data_size, digest); if (ret < 0) return gnutls_assert_val(ret); if (memcmp(digest, cookie.data, COOKIE_MAC_SIZE) != 0) return gnutls_assert_val(GNUTLS_E_BAD_COOKIE); prestate->record_seq = msg[10]; /* client's record seq */ prestate->hsk_read_seq = msg[DTLS_RECORD_HEADER_SIZE+5]; /* client's hsk seq */ prestate->hsk_write_seq = 0;/* we always send zero for this msg */ return 0; }
int _gnutls_pbkdf2_sha1 (const char *P, size_t Plen, const unsigned char *S, size_t Slen, unsigned int c, unsigned char *DK, size_t dkLen) { unsigned int hLen = 20; char U[20]; char T[20]; unsigned int u; unsigned int l; unsigned int r; unsigned int i; unsigned int k; int rc; char *tmp; size_t tmplen = Slen + 4; if (c == 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (dkLen == 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* * * Steps: * * 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and * stop. */ if (dkLen > 4294967295U) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* * 2. Let l be the number of hLen-octet blocks in the derived key, * rounding up, and let r be the number of octets in the last * block: * * l = CEIL (dkLen / hLen) , * r = dkLen - (l - 1) * hLen . * * Here, CEIL (x) is the "ceiling" function, i.e. the smallest * integer greater than, or equal to, x. */ l = ((dkLen - 1) / hLen) + 1; r = dkLen - (l - 1) * hLen; /* * 3. For each block of the derived key apply the function F defined * below to the password P, the salt S, the iteration count c, and * the block index to compute the block: * * T_1 = F (P, S, c, 1) , * T_2 = F (P, S, c, 2) , * ... * T_l = F (P, S, c, l) , * * where the function F is defined as the exclusive-or sum of the * first c iterates of the underlying pseudorandom function PRF * applied to the password P and the concatenation of the salt S * and the block index i: * * F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c * * where * * U_1 = PRF (P, S || INT (i)) , * U_2 = PRF (P, U_1) , * ... * U_c = PRF (P, U_{c-1}) . * * Here, INT (i) is a four-octet encoding of the integer i, most * significant octet first. * * 4. Concatenate the blocks and extract the first dkLen octets to * produce a derived key DK: * * DK = T_1 || T_2 || ... || T_l<0..r-1> * * 5. Output the derived key DK. * * Note. The construction of the function F follows a "belt-and- * suspenders" approach. The iterates U_i are computed recursively to * remove a degree of parallelism from an opponent; they are exclusive- * ored together to reduce concerns about the recursion degenerating * into a small set of values. * */ tmp = gnutls_malloc (tmplen); if (tmp == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } memcpy (tmp, S, Slen); for (i = 1; i <= l; i++) { memset (T, 0, hLen); for (u = 1; u <= c; u++) { if (u == 1) { tmp[Slen + 0] = (i & 0xff000000) >> 24; tmp[Slen + 1] = (i & 0x00ff0000) >> 16; tmp[Slen + 2] = (i & 0x0000ff00) >> 8; tmp[Slen + 3] = (i & 0x000000ff) >> 0; rc = _gnutls_hmac_fast (GNUTLS_MAC_SHA1, P, Plen, tmp, tmplen, U); } else rc = _gnutls_hmac_fast (GNUTLS_MAC_SHA1, P, Plen, U, hLen, U); if (rc < 0) { gnutls_free (tmp); return rc; } for (k = 0; k < hLen; k++) T[k] ^= U[k]; }
/** * gnutls_dtls_cookie_send: * @key: is a random key to be used at cookie generation * @client_data: contains data identifying the client (i.e. address) * @client_data_size: The size of client's data * @prestate: The previous cookie returned by gnutls_dtls_cookie_verify() * @ptr: A transport pointer to be used by @push_func * @push_func: A function that will be used to reply * * This function can be used to prevent denial of service * attacks to a DTLS server by requiring the client to * reply using a cookie sent by this function. That way * it can be ensured that a client we allocated resources * for (i.e. #gnutls_session_t) is the one that the * original incoming packet was originated from. * * Returns: the number of bytes sent, or a negative error code. * * Since: 3.0 **/ int gnutls_dtls_cookie_send(gnutls_datum_t* key, void* client_data, size_t client_data_size, gnutls_dtls_prestate_st* prestate, gnutls_transport_ptr_t ptr, gnutls_push_func push_func) { uint8_t hvr[20+DTLS_HANDSHAKE_HEADER_SIZE+COOKIE_SIZE]; int hvr_size = 0, ret; uint8_t digest[C_HASH_SIZE]; if (key == NULL || key->data == NULL || key->size == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); /* send * struct { * ContentType type - 1 byte GNUTLS_HANDSHAKE; * ProtocolVersion version; - 2 bytes (254,255) * uint16 epoch; - 2 bytes (0, 0) * uint48 sequence_number; - 4 bytes (0,0,0,0) * uint16 length; - 2 bytes (COOKIE_SIZE+1+2)+DTLS_HANDSHAKE_HEADER_SIZE * uint8_t fragment[DTLSPlaintext.length]; * } DTLSPlaintext; * * * struct { * HandshakeType msg_type; 1 byte - GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST * uint24 length; - COOKIE_SIZE+3 * uint16 message_seq; - 2 bytes (0,0) * uint24 fragment_offset; - 3 bytes (0,0,0) * uint24 fragment_length; - same as length * } * * struct { * ProtocolVersion server_version; * uint8_t cookie<0..32>; * } HelloVerifyRequest; */ hvr[hvr_size++] = GNUTLS_HANDSHAKE; /* version */ hvr[hvr_size++] = 254; hvr[hvr_size++] = 255; /* epoch + seq */ memset(&hvr[hvr_size], 0, 8); hvr_size += 7; hvr[hvr_size++] = prestate->record_seq; /* length */ _gnutls_write_uint16(DTLS_HANDSHAKE_HEADER_SIZE+COOKIE_SIZE+3, &hvr[hvr_size]); hvr_size += 2; /* now handshake headers */ hvr[hvr_size++] = GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST; _gnutls_write_uint24(COOKIE_SIZE+3, &hvr[hvr_size]); hvr_size += 3; /* handshake seq */ hvr[hvr_size++] = 0; hvr[hvr_size++] = prestate->hsk_write_seq; _gnutls_write_uint24(0, &hvr[hvr_size]); hvr_size += 3; _gnutls_write_uint24(COOKIE_SIZE+3, &hvr[hvr_size]); hvr_size += 3; /* version */ hvr[hvr_size++] = 254; hvr[hvr_size++] = 255; hvr[hvr_size++] = COOKIE_SIZE; ret = _gnutls_hmac_fast(C_HASH, key->data, key->size, client_data, client_data_size, digest); if (ret < 0) return gnutls_assert_val(ret); memcpy(&hvr[hvr_size], digest, COOKIE_MAC_SIZE); hvr_size+= COOKIE_MAC_SIZE; ret = push_func(ptr, hvr, hvr_size); if (ret < 0) ret = GNUTLS_E_PUSH_ERROR; return ret; }