#include #include #include #include "pair.h" #define RETURN_ERROR(s, m) \ do { handle->status = (s); handle->errmsg = (m); goto error; } while(0) struct SRPUser; struct SRPVerifier; struct pair_client_setup_context { struct SRPUser *user; char *pin; char device_id[PAIR_AP_DEVICE_ID_LEN_MAX]; pair_cb add_cb; void *add_cb_arg; uint8_t public_key[crypto_sign_PUBLICKEYBYTES]; uint8_t private_key[crypto_sign_SECRETKEYBYTES]; const uint8_t *pkA; int pkA_len; uint8_t *pkB; uint64_t pkB_len; const uint8_t *M1; int M1_len; uint8_t *M2; uint64_t M2_len; uint8_t *salt; uint64_t salt_len; // We don't actually use the server's epk and authtag for anything uint8_t *epk; uint64_t epk_len; uint8_t *authtag; uint64_t authtag_len; }; struct pair_server_setup_context { struct SRPVerifier *verifier; char *pin; char device_id[PAIR_AP_DEVICE_ID_LEN_MAX]; pair_cb add_cb; void *add_cb_arg; uint8_t public_key[crypto_sign_PUBLICKEYBYTES]; uint8_t private_key[crypto_sign_SECRETKEYBYTES]; bool is_transient; uint8_t *pkA; uint64_t pkA_len; uint8_t *pkB; int pkB_len; uint8_t *b; int b_len; uint8_t *M1; uint64_t M1_len; const uint8_t *M2; int M2_len; uint8_t *v; int v_len; uint8_t *salt; int salt_len; }; enum pair_status { PAIR_STATUS_IN_PROGRESS, PAIR_STATUS_COMPLETED, PAIR_STATUS_AUTH_FAILED, PAIR_STATUS_INVALID, }; struct pair_setup_context { struct pair_definition *type; enum pair_status status; const char *errmsg; struct pair_result result; char result_str[256]; // Holds the hex string version of the keys that pair_verify_new() needs // Hex-formatet concatenation of public + private, 0-terminated char auth_key[2 * (crypto_sign_PUBLICKEYBYTES + crypto_sign_SECRETKEYBYTES) + 1]; union pair_setup_union { struct pair_client_setup_context client; struct pair_server_setup_context server; } sctx; }; struct pair_client_verify_context { char device_id[PAIR_AP_DEVICE_ID_LEN_MAX]; // These are the keys that were registered with the server in pair-setup uint8_t client_public_key[crypto_sign_PUBLICKEYBYTES]; // 32 uint8_t client_private_key[crypto_sign_SECRETKEYBYTES]; // 64 bool verify_server_signature; uint8_t server_fruit_public_key[64]; // Not sure why it has this length in fruit mode uint8_t server_public_key[crypto_sign_PUBLICKEYBYTES]; // 32 // For establishing the shared secret for encrypted communication uint8_t client_eph_public_key[crypto_box_PUBLICKEYBYTES]; // 32 uint8_t client_eph_private_key[crypto_box_SECRETKEYBYTES]; // 32 uint8_t server_eph_public_key[crypto_box_PUBLICKEYBYTES]; // 32 uint8_t shared_secret[crypto_scalarmult_BYTES]; // 32 }; struct pair_server_verify_context { char device_id[PAIR_AP_DEVICE_ID_LEN_MAX]; // Same keys as used for pair-setup, derived from device_id uint8_t server_public_key[crypto_sign_PUBLICKEYBYTES]; // 32 uint8_t server_private_key[crypto_sign_SECRETKEYBYTES]; // 64 bool verify_client_signature; pair_cb get_cb; void *get_cb_arg; // For establishing the shared secret for encrypted communication uint8_t server_eph_public_key[crypto_box_PUBLICKEYBYTES]; // 32 uint8_t server_eph_private_key[crypto_box_SECRETKEYBYTES]; // 32 uint8_t client_eph_public_key[crypto_box_PUBLICKEYBYTES]; // 32 uint8_t shared_secret[crypto_scalarmult_BYTES]; // 32 }; struct pair_verify_context { struct pair_definition *type; enum pair_status status; const char *errmsg; struct pair_result result; union pair_verify_union { struct pair_client_verify_context client; struct pair_server_verify_context server; } vctx; }; struct pair_cipher_context { struct pair_definition *type; uint8_t encryption_key[32]; uint8_t decryption_key[32]; uint64_t encryption_counter; uint64_t decryption_counter; // For rollback uint64_t encryption_counter_prev; uint64_t decryption_counter_prev; const char *errmsg; }; struct pair_definition { int (*pair_setup_new)(struct pair_setup_context *sctx, const char *pin, pair_cb add_cb, void *cb_arg, const char *device_id); void (*pair_setup_free)(struct pair_setup_context *sctx); int (*pair_setup_result)(struct pair_setup_context *sctx); uint8_t *(*pair_setup_request1)(size_t *len, struct pair_setup_context *sctx); uint8_t *(*pair_setup_request2)(size_t *len, struct pair_setup_context *sctx); uint8_t *(*pair_setup_request3)(size_t *len, struct pair_setup_context *sctx); int (*pair_setup_response1)(struct pair_setup_context *sctx, const uint8_t *in, size_t in_len); int (*pair_setup_response2)(struct pair_setup_context *sctx, const uint8_t *in, size_t in_len); int (*pair_setup_response3)(struct pair_setup_context *sctx, const uint8_t *in, size_t in_len); int (*pair_verify_new)(struct pair_verify_context *vctx, const char *client_setup_keys, pair_cb cb, void *cb_arg, const char *device_id); void (*pair_verify_free)(struct pair_verify_context *vctx); int (*pair_verify_result)(struct pair_verify_context *vctx); uint8_t *(*pair_verify_request1)(size_t *len, struct pair_verify_context *vctx); uint8_t *(*pair_verify_request2)(size_t *len, struct pair_verify_context *vctx); int (*pair_verify_response1)(struct pair_verify_context *vctx, const uint8_t *in, size_t in_len); int (*pair_verify_response2)(struct pair_verify_context *vctx, const uint8_t *in, size_t in_len); int (*pair_add)(uint8_t **out, size_t *out_len, pair_cb cb, void *cb_arg, const uint8_t *in, size_t in_len); int (*pair_remove)(uint8_t **out, size_t *out_len, pair_cb cb, void *cb_arg, const uint8_t *in, size_t in_len); int (*pair_list)(uint8_t **out, size_t *out_len, pair_list_cb cb, void *cb_arg, const uint8_t *in, size_t in_len); struct pair_cipher_context *(*pair_cipher_new)(struct pair_definition *type, int channel, const uint8_t *shared_secret, size_t shared_secret_len); void (*pair_cipher_free)(struct pair_cipher_context *cctx); ssize_t (*pair_encrypt)(uint8_t **ciphertext, size_t *ciphertext_len, const uint8_t *plaintext, size_t plaintext_len, struct pair_cipher_context *cctx); ssize_t (*pair_decrypt)(uint8_t **plaintext, size_t *plaintext_len, const uint8_t *ciphertext, size_t ciphertext_len, struct pair_cipher_context *cctx); int (*pair_state_get)(const char **errmsg, const uint8_t *in, size_t in_len); void (*pair_public_key_get)(uint8_t server_public_key[32], const char *device_id); }; /* ----------------------------- INITIALIZATION ---------------------------- */ bool is_initialized(void); /* -------------------- GCRYPT AND OPENSSL COMPABILITY --------------------- */ /* partly borrowed from ffmpeg (rtmpdh.c) */ #if CONFIG_GCRYPT #include #define SHA512_DIGEST_LENGTH 64 #define bnum_new(bn) \ do { \ if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { \ if (!gcry_check_version("1.5.4")) \ abort(); \ gcry_control(GCRYCTL_DISABLE_SECMEM, 0); \ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); \ } \ bn = gcry_mpi_new(1); \ } while (0) #define bnum_free(bn) gcry_mpi_release(bn) #define bnum_num_bytes(bn) (gcry_mpi_get_nbits(bn) + 7) / 8 #define bnum_is_zero(bn) (gcry_mpi_cmp_ui(bn, (unsigned long)0) == 0) #define bnum_bn2bin(bn, buf, len) gcry_mpi_print(GCRYMPI_FMT_USG, buf, len, NULL, bn) #define bnum_bin2bn(bn, buf, len) gcry_mpi_scan(&bn, GCRYMPI_FMT_USG, buf, len, NULL) #define bnum_hex2bn(bn, buf) gcry_mpi_scan(&bn, GCRYMPI_FMT_HEX, buf, 0, 0) #define bnum_random(bn, num_bits) gcry_mpi_randomize(bn, num_bits, GCRY_WEAK_RANDOM) #define bnum_add(bn, a, b) gcry_mpi_add(bn, a, b) #define bnum_sub(bn, a, b) gcry_mpi_sub(bn, a, b) #define bnum_mul(bn, a, b) gcry_mpi_mul(bn, a, b) #define bnum_mod(bn, a, b) gcry_mpi_mod(bn, a, b) typedef gcry_mpi_t bnum; __attribute__((unused)) static void bnum_modexp(bnum bn, bnum y, bnum q, bnum p) { gcry_mpi_powm(bn, y, q, p); } __attribute__((unused)) static void bnum_modadd(bnum bn, bnum a, bnum b, bnum m) { gcry_mpi_addm(bn, a, b, m); } #elif CONFIG_OPENSSL #include #include #include #include #include #define bnum_new(bn) bn = BN_new() #define bnum_free(bn) BN_free(bn) #define bnum_num_bytes(bn) BN_num_bytes(bn) #define bnum_is_zero(bn) BN_is_zero(bn) #define bnum_bn2bin(bn, buf, len) BN_bn2bin(bn, buf) #define bnum_bin2bn(bn, buf, len) bn = BN_bin2bn(buf, len, 0) #define bnum_hex2bn(bn, buf) BN_hex2bn(&bn, buf) #define bnum_random(bn, num_bits) BN_rand(bn, num_bits, 0, 0) #define bnum_add(bn, a, b) BN_add(bn, a, b) #define bnum_sub(bn, a, b) BN_sub(bn, a, b) typedef BIGNUM* bnum; __attribute__((unused)) static void bnum_mul(bnum bn, bnum a, bnum b) { // No error handling BN_CTX *ctx = BN_CTX_new(); BN_mul(bn, a, b, ctx); BN_CTX_free(ctx); } __attribute__((unused)) static void bnum_mod(bnum bn, bnum a, bnum b) { // No error handling BN_CTX *ctx = BN_CTX_new(); BN_mod(bn, a, b, ctx); BN_CTX_free(ctx); } __attribute__((unused)) static void bnum_modexp(bnum bn, bnum y, bnum q, bnum p) { // No error handling BN_CTX *ctx = BN_CTX_new(); BN_mod_exp(bn, y, q, p, ctx); BN_CTX_free(ctx); } __attribute__((unused)) static void bnum_modadd(bnum bn, bnum a, bnum b, bnum m) { // No error handling BN_CTX *ctx = BN_CTX_new(); BN_mod_add(bn, a, b, m, ctx); BN_CTX_free(ctx); } #endif /* -------------------------- SHARED HASHING HELPERS ------------------------ */ #ifdef CONFIG_OPENSSL enum hash_alg { HASH_SHA1, HASH_SHA224, HASH_SHA256, HASH_SHA384, HASH_SHA512, }; #elif CONFIG_GCRYPT enum hash_alg { HASH_SHA1 = GCRY_MD_SHA1, HASH_SHA224 = GCRY_MD_SHA224, HASH_SHA256 = GCRY_MD_SHA256, HASH_SHA384 = GCRY_MD_SHA384, HASH_SHA512 = GCRY_MD_SHA512, }; #endif #if CONFIG_OPENSSL typedef union { SHA_CTX sha; SHA256_CTX sha256; SHA512_CTX sha512; } HashCTX; #elif CONFIG_GCRYPT typedef gcry_md_hd_t HashCTX; #endif int hash_init(enum hash_alg alg, HashCTX *c); int hash_update(enum hash_alg alg, HashCTX *c, const void *data, size_t len); int hash_final(enum hash_alg alg, HashCTX *c, unsigned char *md); unsigned char * hash(enum hash_alg alg, const unsigned char *d, size_t n, unsigned char *md); int hash_length(enum hash_alg alg); int hash_ab(enum hash_alg alg, unsigned char *md, const unsigned char *m1, int m1_len, const unsigned char *m2, int m2_len); bnum H_nn_pad(enum hash_alg alg, const bnum n1, const bnum n2, int padded_len); bnum H_ns(enum hash_alg alg, const bnum n, const unsigned char *bytes, int len_bytes); void update_hash_n(enum hash_alg alg, HashCTX *ctx, const bnum n); void hash_num(enum hash_alg alg, const bnum n, unsigned char *dest); /* ----------------------------- OTHER HELPERS -------------------------------*/ #ifdef DEBUG_PAIR void hexdump(const char *msg, uint8_t *mem, size_t len); void bnum_dump(const char *msg, bnum n); #endif