The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
Functions
crypto.c File Reference

The cryptographic primitives of EAP-PSK (RFC 4764). More...

#include <freeradius-devel/util/misc.h>
#include <openssl/evp.h>
#include <openssl/cmac.h>
#include <openssl/crypto.h>
#include "crypto.h"
+ Include dependency graph for crypto.c:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

static int aes128_ctr (uint8_t *out, uint8_t const key[static 16], uint8_t const ctr[static 16], uint8_t const *in, size_t len)
 AES-128 in counter mode.
 
static USES_APPLE_DEPRECATED_API int aes128_ecb_block (uint8_t out[static 16], uint8_t const key[static 16], uint8_t const in[static 16])
 A single AES-128 ECB block encryption: out = AES-128(key, in)
 
static int eap_psk_cmac (uint8_t mac[static 16], uint8_t const key[static 16], uint8_t const *seg1, size_t len1, uint8_t const *seg2, size_t len2, uint8_t const *seg3, size_t len3, uint8_t const *seg4, size_t len4)
 AES-128 CMAC over one or more concatenated buffers.
 
static int eap_psk_counter_mode (uint8_t *out, uint8_t const key[static 16], uint8_t const input[static 16], size_t count)
 The "modified counter mode" of RFC 4764 Sections 3.1 and 3.2.
 
int eap_psk_derive_ak_kdk (uint8_t ak[static EAP_PSK_AK_LEN], uint8_t kdk[static EAP_PSK_KDK_LEN], uint8_t const psk[static EAP_PSK_PSK_LEN])
 Key setup: derive AK (counter 1) and KDK (counter 2) from the PSK.
 
int eap_psk_derive_keys (uint8_t tek[static EAP_PSK_TEK_LEN], uint8_t msk[static EAP_PSK_MSK_LEN], uint8_t emsk[static EAP_PSK_EMSK_LEN], uint8_t const kdk[static EAP_PSK_KDK_LEN], uint8_t const rand_p[static EAP_PSK_RAND_LEN])
 Session-key derivation: expand RAND_P under KDK into nine output blocks.
 
int eap_psk_mac_p (uint8_t mac_p[static EAP_PSK_MAC_LEN], uint8_t const ak[static EAP_PSK_AK_LEN], uint8_t const *id_p, size_t id_p_len, uint8_t const *id_s, size_t id_s_len, uint8_t const rand_s[static EAP_PSK_RAND_LEN], uint8_t const rand_p[static EAP_PSK_RAND_LEN])
 Compute MAC_P = CMAC-AES-128(AK, ID_P || ID_S || RAND_S || RAND_P)
 
int eap_psk_mac_s (uint8_t mac_s[static EAP_PSK_MAC_LEN], uint8_t const ak[static EAP_PSK_AK_LEN], uint8_t const *id_s, size_t id_s_len, uint8_t const rand_p[static EAP_PSK_RAND_LEN])
 Compute MAC_S = CMAC-AES-128(AK, ID_S || RAND_P)
 
static void eap_psk_nonce_block (uint8_t block[static 16], uint32_t nonce)
 Build the 16-byte EAX nonce block from the 4-byte EAP-PSK Nonce N.
 
static int eap_psk_omac (uint8_t out[static 16], uint8_t const key[static 16], uint8_t t, uint8_t const *data, size_t data_len)
 The tweaked OMAC used by EAX: OMAC^t(M) = CMAC(K, [t]_16 || M)
 
int eap_psk_pchannel_decrypt (uint8_t *plain, uint8_t const tek[static EAP_PSK_TEK_LEN], uint32_t nonce, uint8_t const *header, size_t header_len, uint8_t const *cipher, size_t cipher_len, uint8_t const tag[static EAP_PSK_TAG_LEN])
 EAX decrypt-and-verify for the protected channel (RFC 4764 Section 3.3)
 
int eap_psk_pchannel_encrypt (uint8_t *cipher, uint8_t tag[static EAP_PSK_TAG_LEN], uint8_t const tek[static EAP_PSK_TEK_LEN], uint32_t nonce, uint8_t const *header, size_t header_len, uint8_t const *plain, size_t plain_len)
 EAX encrypt for the protected channel (RFC 4764 Section 3.3)
 

Detailed Description

The cryptographic primitives of EAP-PSK (RFC 4764).

Id
1fe763077bf31b06022d32388b2df92719e33f7f

EAP-PSK is built entirely on AES-128. This file implements, using the OpenSSL EVP and CMAC APIs:

Definition in file crypto.c.

Function Documentation

◆ aes128_ctr()

static int aes128_ctr ( uint8_t out,
uint8_t const  key[static 16],
uint8_t const  ctr[static 16],
uint8_t const *  in,
size_t  len 
)
static

AES-128 in counter mode.

OpenSSL uses the 16-byte IV as the initial counter block and increments the whole 128-bit value as a big-endian integer, which is exactly what EAX (and hence EAP-PSK) requires. CTR is symmetric, so the function serves both encryption and decryption.

Parameters
[out]outreceives len bytes.
[in]keythe 16-byte AES key.
[in]ctrthe initial 16-byte counter block.
[in]inthe data to encrypt or decrypt.
[in]lenlength of in.
Returns
  • 0 on success.
  • -1 on OpenSSL failure.

Definition at line 93 of file crypto.c.

+ Here is the caller graph for this function:

◆ aes128_ecb_block()

static USES_APPLE_DEPRECATED_API int aes128_ecb_block ( uint8_t  out[static 16],
uint8_t const  key[static 16],
uint8_t const  in[static 16] 
)
static

A single AES-128 ECB block encryption: out = AES-128(key, in)

Parameters
[out]outthe encrypted 16-byte block.
[in]keythe 16-byte AES key.
[in]inthe 16-byte block to encrypt.
Returns
  • 0 on success.
  • -1 on OpenSSL failure.

Definition at line 52 of file crypto.c.

+ Here is the caller graph for this function:

◆ eap_psk_cmac()

static int eap_psk_cmac ( uint8_t  mac[static 16],
uint8_t const  key[static 16],
uint8_t const *  seg1,
size_t  len1,
uint8_t const *  seg2,
size_t  len2,
uint8_t const *  seg3,
size_t  len3,
uint8_t const *  seg4,
size_t  len4 
)
static

AES-128 CMAC over one or more concatenated buffers.

A NULL buffer is skipped, so callers can pass a fixed set of segments.

The low-level CMAC API is used because it is portable across OpenSSL 1.1 and 3.x; OpenSSL 3.0 deprecates it in favour of EVP_MAC, so the deprecation warning is suppressed the same way the rest of the tree handles deprecated OpenSSL calls.

Parameters
[out]macthe computed 16-byte CMAC.
[in]keythe 16-byte AES key.
[in]seg1first data segment. May be NULL.
[in]len1length of seg1.
[in]seg2second data segment. May be NULL.
[in]len2length of seg2.
[in]seg3third data segment. May be NULL.
[in]len3length of seg3.
[in]seg4fourth data segment. May be NULL.
[in]len4length of seg4.
Returns
  • 0 on success.
  • -1 on OpenSSL failure.

Definition at line 235 of file crypto.c.

+ Here is the caller graph for this function:

◆ eap_psk_counter_mode()

static int eap_psk_counter_mode ( uint8_t out,
uint8_t const  key[static 16],
uint8_t const  input[static 16],
size_t  count 
)
static

The "modified counter mode" of RFC 4764 Sections 3.1 and 3.2.

A length-increasing function that expands one 16-byte input block into 'count' output blocks:

 hash    = AES-128(key, input)
 out_i   = AES-128(key, hash XOR c_i)       for i = 1 .. count

where c_i is the integer i encoded as a 16-byte block. Since i is always small (<= 9) only the low-order byte is ever non-zero.

Parameters
[out]outreceives count * 16 bytes.
[in]keythe 16-byte AES key.
[in]inputthe 16-byte block to expand.
[in]counthow many output blocks to produce.
Returns
  • 0 on success.
  • -1 on OpenSSL failure.

Definition at line 133 of file crypto.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eap_psk_derive_ak_kdk()

int eap_psk_derive_ak_kdk ( uint8_t  ak[static EAP_PSK_AK_LEN],
uint8_t  kdk[static EAP_PSK_KDK_LEN],
uint8_t const  psk[static EAP_PSK_PSK_LEN] 
)

Key setup: derive AK (counter 1) and KDK (counter 2) from the PSK.

Expands a constant all-zero input block under the PSK using the modified counter mode. See RFC 4764 Section 3.1, Figure 3.

Parameters
[out]akthe derived authentication key.
[out]kdkthe derived key-derivation key.
[in]pskthe 16-byte pre-shared key.
Returns
  • 0 on success.
  • -1 on OpenSSL failure.

Definition at line 164 of file crypto.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eap_psk_derive_keys()

int eap_psk_derive_keys ( uint8_t  tek[static EAP_PSK_TEK_LEN],
uint8_t  msk[static EAP_PSK_MSK_LEN],
uint8_t  emsk[static EAP_PSK_EMSK_LEN],
uint8_t const  kdk[static EAP_PSK_KDK_LEN],
uint8_t const  rand_p[static EAP_PSK_RAND_LEN] 
)

Session-key derivation: expand RAND_P under KDK into nine output blocks.

Block 1 is the TEK, blocks 2..5 are the MSK, and blocks 6..9 are the EMSK. See RFC 4764 Section 3.2, Figure 7.

Parameters
[out]tekthe transient EAP key, used for the protected channel.
[out]mskthe 64-byte master session key.
[out]emskthe 64-byte extended master session key.
[in]kdkthe key-derivation key from eap_psk_derive_ak_kdk().
[in]rand_pthe peer's 16-byte nonce.
Returns
  • 0 on success.
  • -1 on OpenSSL failure.

Definition at line 194 of file crypto.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eap_psk_mac_p()

int eap_psk_mac_p ( uint8_t  mac_p[static EAP_PSK_MAC_LEN],
uint8_t const  ak[static EAP_PSK_AK_LEN],
uint8_t const *  id_p,
size_t  id_p_len,
uint8_t const *  id_s,
size_t  id_s_len,
uint8_t const  rand_s[static EAP_PSK_RAND_LEN],
uint8_t const  rand_p[static EAP_PSK_RAND_LEN] 
)

Compute MAC_P = CMAC-AES-128(AK, ID_P || ID_S || RAND_S || RAND_P)

The peer proves possession of the PSK with MAC_P in the second message. See RFC 4764 Section 5.2.

Parameters
[out]mac_pthe computed 16-byte MAC.
[in]akthe authentication key.
[in]id_pthe peer's NAI. May not be NULL terminated.
[in]id_p_lenlength of id_p.
[in]id_sthe server's NAI.
[in]id_s_lenlength of id_s.
[in]rand_sthe server's nonce.
[in]rand_pthe peer's nonce.
Returns
  • 0 on success.
  • -1 on OpenSSL failure.

Definition at line 283 of file crypto.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eap_psk_mac_s()

int eap_psk_mac_s ( uint8_t  mac_s[static EAP_PSK_MAC_LEN],
uint8_t const  ak[static EAP_PSK_AK_LEN],
uint8_t const *  id_s,
size_t  id_s_len,
uint8_t const  rand_p[static EAP_PSK_RAND_LEN] 
)

Compute MAC_S = CMAC-AES-128(AK, ID_S || RAND_P)

The server proves possession of the PSK with MAC_S in the third message. See RFC 4764 Section 5.3.

Parameters
[out]mac_sthe computed 16-byte MAC.
[in]akthe authentication key.
[in]id_sthe server's NAI.
[in]id_s_lenlength of id_s.
[in]rand_pthe peer's nonce.
Returns
  • 0 on success.
  • -1 on OpenSSL failure.

Definition at line 311 of file crypto.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eap_psk_nonce_block()

static void eap_psk_nonce_block ( uint8_t  block[static 16],
uint32_t  nonce 
)
static

Build the 16-byte EAX nonce block from the 4-byte EAP-PSK Nonce N.

N is padded with 96 zero high-order bits, i.e. 12 zero bytes followed by the 4-byte big-endian counter (RFC 4764 Section 3.3).

Parameters
[out]blockthe 16-byte nonce block.
[in]noncethe PCHANNEL counter.

Definition at line 361 of file crypto.c.

+ Here is the caller graph for this function:

◆ eap_psk_omac()

static int eap_psk_omac ( uint8_t  out[static 16],
uint8_t const  key[static 16],
uint8_t  t,
uint8_t const *  data,
size_t  data_len 
)
static

The tweaked OMAC used by EAX: OMAC^t(M) = CMAC(K, [t]_16 || M)

[t]_16 is the integer t encoded as a 16-byte block. t is only ever 0, 1 or 2 here, so only the low-order byte is non-zero.

Parameters
[out]outthe computed 16-byte OMAC.
[in]keythe 16-byte AES key.
[in]tthe OMAC tweak.
[in]datathe data to authenticate.
[in]data_lenlength of data.
Returns
  • 0 on success.
  • -1 on OpenSSL failure.

Definition at line 337 of file crypto.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eap_psk_pchannel_decrypt()

int eap_psk_pchannel_decrypt ( uint8_t plain,
uint8_t const  tek[static EAP_PSK_TEK_LEN],
uint32_t  nonce,
uint8_t const *  header,
size_t  header_len,
uint8_t const *  cipher,
size_t  cipher_len,
uint8_t const  tag[static EAP_PSK_TAG_LEN] 
)

EAX decrypt-and-verify for the protected channel (RFC 4764 Section 3.3)

Recomputes the tag over the received ciphertext and header, and compares the result (in constant time) against the received tag. Only if the tags match is the ciphertext decrypted.

Parameters
[out]plainreceives cipher_len bytes of plaintext.
[in]tekthe transient EAP key.
[in]noncethe 4-byte PCHANNEL counter (1 for the fourth message).
[in]headerthe EAX header H to authenticate.
[in]header_lenlength of header.
[in]cipherthe ciphertext to verify and decrypt.
[in]cipher_lenlength of cipher.
[in]tagthe received 16-byte authentication tag.
Returns
  • 0 if the tag is valid and the plaintext was recovered.
  • -1 on a bad tag or an OpenSSL error.

Definition at line 439 of file crypto.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eap_psk_pchannel_encrypt()

int eap_psk_pchannel_encrypt ( uint8_t cipher,
uint8_t  tag[static EAP_PSK_TAG_LEN],
uint8_t const  tek[static EAP_PSK_TEK_LEN],
uint32_t  nonce,
uint8_t const *  header,
size_t  header_len,
uint8_t const *  plain,
size_t  plain_len 
)

EAX encrypt for the protected channel (RFC 4764 Section 3.3)

Computes:

 N' = OMAC^0(nonce_block)
 H' = OMAC^1(header)
 C  = CTR_{N'}(plain)
 C' = OMAC^2(C)
 tag = N' XOR H' XOR C'

Either the plaintext or its length may be zero (EAP-PSK only ever protects a single byte, but the code does not rely on that).

Parameters
[out]cipherreceives plain_len bytes of ciphertext.
[out]tagreceives the 16-byte authentication tag.
[in]tekthe transient EAP key.
[in]noncethe 4-byte PCHANNEL counter (0 for the third message).
[in]headerthe EAX header H to authenticate.
[in]header_lenlength of header.
[in]plainthe plaintext to encrypt.
[in]plain_lenlength of plain.
Returns
  • 0 on success.
  • -1 on OpenSSL failure.

Definition at line 395 of file crypto.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function: