807 lines
19 KiB
C
807 lines
19 KiB
C
/*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
|
* so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h> // for isprint()
|
|
#include <assert.h>
|
|
|
|
#include <sodium.h>
|
|
|
|
#include "pair.h"
|
|
#include "pair-internal.h"
|
|
|
|
extern struct pair_definition pair_client_fruit;
|
|
extern struct pair_definition pair_client_homekit_normal;
|
|
extern struct pair_definition pair_client_homekit_transient;
|
|
extern struct pair_definition pair_server_homekit;
|
|
|
|
// Must be in sync with enum pair_type
|
|
static struct pair_definition *pair[] = {
|
|
&pair_client_fruit,
|
|
&pair_client_homekit_normal,
|
|
&pair_client_homekit_transient,
|
|
&pair_server_homekit,
|
|
};
|
|
|
|
/* ------------------------------ INITIALIZATION ---------------------------- */
|
|
|
|
bool
|
|
is_initialized(void)
|
|
{
|
|
if (sodium_init() == -1)
|
|
return false;
|
|
|
|
#if CONFIG_GCRYPT
|
|
// According to libgcrypt documentation: "It is important that these
|
|
// initialization steps are not done by a library but by the actual
|
|
// application. A library using Libgcrypt might want to check for finished
|
|
// initialization using:"
|
|
if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P))
|
|
return false;
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/* -------------------------- SHARED HASHING HELPERS ------------------------ */
|
|
|
|
int
|
|
hash_init(enum hash_alg alg, HashCTX *c)
|
|
{
|
|
#if CONFIG_OPENSSL
|
|
switch (alg)
|
|
{
|
|
case HASH_SHA1 : return SHA1_Init(&c->sha);
|
|
case HASH_SHA224: return SHA224_Init(&c->sha256);
|
|
case HASH_SHA256: return SHA256_Init(&c->sha256);
|
|
case HASH_SHA384: return SHA384_Init(&c->sha512);
|
|
case HASH_SHA512: return SHA512_Init(&c->sha512);
|
|
default:
|
|
return -1;
|
|
};
|
|
#elif CONFIG_GCRYPT
|
|
gcry_error_t err;
|
|
|
|
err = gcry_md_open(c, alg, 0);
|
|
|
|
if (err)
|
|
return -1;
|
|
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
hash_update(enum hash_alg alg, HashCTX *c, const void *data, size_t len)
|
|
{
|
|
#if CONFIG_OPENSSL
|
|
switch (alg)
|
|
{
|
|
case HASH_SHA1 : return SHA1_Update(&c->sha, data, len);
|
|
case HASH_SHA224: return SHA224_Update(&c->sha256, data, len);
|
|
case HASH_SHA256: return SHA256_Update(&c->sha256, data, len);
|
|
case HASH_SHA384: return SHA384_Update(&c->sha512, data, len);
|
|
case HASH_SHA512: return SHA512_Update(&c->sha512, data, len);
|
|
default:
|
|
return -1;
|
|
};
|
|
#elif CONFIG_GCRYPT
|
|
gcry_md_write(*c, data, len);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
hash_final(enum hash_alg alg, HashCTX *c, unsigned char *md)
|
|
{
|
|
#if CONFIG_OPENSSL
|
|
switch (alg)
|
|
{
|
|
case HASH_SHA1 : return SHA1_Final(md, &c->sha);
|
|
case HASH_SHA224: return SHA224_Final(md, &c->sha256);
|
|
case HASH_SHA256: return SHA256_Final(md, &c->sha256);
|
|
case HASH_SHA384: return SHA384_Final(md, &c->sha512);
|
|
case HASH_SHA512: return SHA512_Final(md, &c->sha512);
|
|
default:
|
|
return -1;
|
|
};
|
|
#elif CONFIG_GCRYPT
|
|
unsigned char *buf = gcry_md_read(*c, alg);
|
|
if (!buf)
|
|
return -1;
|
|
|
|
memcpy(md, buf, gcry_md_get_algo_dlen(alg));
|
|
gcry_md_close(*c);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
unsigned char *
|
|
hash(enum hash_alg alg, const unsigned char *d, size_t n, unsigned char *md)
|
|
{
|
|
#if CONFIG_OPENSSL
|
|
switch (alg)
|
|
{
|
|
case HASH_SHA1 : return SHA1(d, n, md);
|
|
case HASH_SHA224: return SHA224(d, n, md);
|
|
case HASH_SHA256: return SHA256(d, n, md);
|
|
case HASH_SHA384: return SHA384(d, n, md);
|
|
case HASH_SHA512: return SHA512(d, n, md);
|
|
default:
|
|
return NULL;
|
|
};
|
|
#elif CONFIG_GCRYPT
|
|
gcry_md_hash_buffer(alg, md, d, n);
|
|
return md;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
hash_length(enum hash_alg alg)
|
|
{
|
|
#if CONFIG_OPENSSL
|
|
switch (alg)
|
|
{
|
|
case HASH_SHA1 : return SHA_DIGEST_LENGTH;
|
|
case HASH_SHA224: return SHA224_DIGEST_LENGTH;
|
|
case HASH_SHA256: return SHA256_DIGEST_LENGTH;
|
|
case HASH_SHA384: return SHA384_DIGEST_LENGTH;
|
|
case HASH_SHA512: return SHA512_DIGEST_LENGTH;
|
|
default:
|
|
return -1;
|
|
};
|
|
#elif CONFIG_GCRYPT
|
|
return gcry_md_get_algo_dlen(alg);
|
|
#endif
|
|
}
|
|
|
|
int
|
|
hash_ab(enum hash_alg alg, unsigned char *md, const unsigned char *m1, int m1_len, const unsigned char *m2, int m2_len)
|
|
{
|
|
HashCTX ctx;
|
|
|
|
hash_init(alg, &ctx);
|
|
hash_update(alg, &ctx, m1, m1_len);
|
|
hash_update(alg, &ctx, m2, m2_len);
|
|
return hash_final(alg, &ctx, md);
|
|
}
|
|
|
|
// See rfc5054 PAD()
|
|
bnum
|
|
H_nn_pad(enum hash_alg alg, const bnum n1, const bnum n2, int padded_len)
|
|
{
|
|
bnum bn;
|
|
unsigned char *bin;
|
|
unsigned char buff[SHA512_DIGEST_LENGTH];
|
|
int len_n1 = bnum_num_bytes(n1);
|
|
int len_n2 = bnum_num_bytes(n2);
|
|
int nbytes = 2 * padded_len;
|
|
int offset_n1 = padded_len - len_n1;
|
|
int offset_n2 = nbytes - len_n2;
|
|
|
|
assert(len_n1 <= padded_len);
|
|
assert(len_n2 <= padded_len);
|
|
|
|
bin = calloc(1, nbytes);
|
|
|
|
bnum_bn2bin(n1, bin + offset_n1, len_n1);
|
|
bnum_bn2bin(n2, bin + offset_n2, len_n2);
|
|
hash(alg, bin, nbytes, buff);
|
|
free(bin);
|
|
bnum_bin2bn(bn, buff, hash_length(alg));
|
|
return bn;
|
|
}
|
|
|
|
bnum
|
|
H_ns(enum hash_alg alg, const bnum n, const unsigned char *bytes, int len_bytes)
|
|
{
|
|
bnum bn;
|
|
unsigned char buff[SHA512_DIGEST_LENGTH];
|
|
int len_n = bnum_num_bytes(n);
|
|
int nbytes = len_n + len_bytes;
|
|
unsigned char *bin = malloc(nbytes);
|
|
|
|
bnum_bn2bin(n, bin, len_n);
|
|
memcpy(bin + len_n, bytes, len_bytes);
|
|
hash(alg, bin, nbytes, buff);
|
|
free(bin);
|
|
bnum_bin2bn(bn, buff, hash_length(alg));
|
|
return bn;
|
|
}
|
|
|
|
void
|
|
update_hash_n(enum hash_alg alg, HashCTX *ctx, const bnum n)
|
|
{
|
|
unsigned long len = bnum_num_bytes(n);
|
|
unsigned char *n_bytes = malloc(len);
|
|
|
|
bnum_bn2bin(n, n_bytes, len);
|
|
hash_update(alg, ctx, n_bytes, len);
|
|
free(n_bytes);
|
|
}
|
|
|
|
void
|
|
hash_num(enum hash_alg alg, const bnum n, unsigned char *dest)
|
|
{
|
|
int nbytes = bnum_num_bytes(n);
|
|
unsigned char *bin = malloc(nbytes);
|
|
|
|
bnum_bn2bin(n, bin, nbytes);
|
|
hash( alg, bin, nbytes, dest );
|
|
free(bin);
|
|
}
|
|
|
|
|
|
/* ----------------------------- OTHER HELPERS -------------------------------*/
|
|
|
|
#ifdef DEBUG_PAIR
|
|
void
|
|
hexdump(const char *msg, uint8_t *mem, size_t len)
|
|
{
|
|
int i, j;
|
|
int hexdump_cols = 16;
|
|
|
|
if (msg)
|
|
printf("%s", msg);
|
|
|
|
for (i = 0; i < len + ((len % hexdump_cols) ? (hexdump_cols - len % hexdump_cols) : 0); i++)
|
|
{
|
|
if(i % hexdump_cols == 0)
|
|
printf("0x%06x: ", i);
|
|
|
|
if (i < len)
|
|
printf("%02x ", 0xFF & ((char*)mem)[i]);
|
|
else
|
|
printf(" ");
|
|
|
|
if (i % hexdump_cols == (hexdump_cols - 1))
|
|
{
|
|
for (j = i - (hexdump_cols - 1); j <= i; j++)
|
|
{
|
|
if (j >= len)
|
|
putchar(' ');
|
|
else if (isprint(((char*)mem)[j]))
|
|
putchar(0xFF & ((char*)mem)[j]);
|
|
else
|
|
putchar('.');
|
|
}
|
|
|
|
putchar('\n');
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
bnum_dump(const char *msg, bnum n)
|
|
{
|
|
int len_n = bnum_num_bytes(n);
|
|
uint8_t *bin = calloc(1, len_n);
|
|
bnum_bn2bin(n, bin, len_n);
|
|
hexdump(msg, bin, len_n);
|
|
free(bin);
|
|
}
|
|
#endif
|
|
|
|
|
|
/* ----------------------------------- API -----------------------------------*/
|
|
|
|
struct pair_setup_context *
|
|
pair_setup_new(enum pair_type type, const char *pin, pair_cb add_cb, void *cb_arg, const char *device_id)
|
|
{
|
|
struct pair_setup_context *sctx;
|
|
|
|
if (!pair[type]->pair_setup_new)
|
|
return NULL;
|
|
|
|
sctx = calloc(1, sizeof(struct pair_setup_context));
|
|
if (!sctx)
|
|
return NULL;
|
|
|
|
sctx->type = pair[type];
|
|
|
|
if (pair[type]->pair_setup_new(sctx, pin, add_cb, cb_arg, device_id) < 0)
|
|
{
|
|
free(sctx);
|
|
return NULL;
|
|
}
|
|
|
|
return sctx;
|
|
}
|
|
|
|
void
|
|
pair_setup_free(struct pair_setup_context *sctx)
|
|
{
|
|
if (!sctx)
|
|
return;
|
|
|
|
if (sctx->type->pair_setup_free)
|
|
sctx->type->pair_setup_free(sctx);
|
|
|
|
free(sctx);
|
|
}
|
|
|
|
const char *
|
|
pair_setup_errmsg(struct pair_setup_context *sctx)
|
|
{
|
|
return sctx->errmsg;
|
|
}
|
|
|
|
int
|
|
pair_setup(uint8_t **out, size_t *out_len, struct pair_setup_context *sctx, const uint8_t *in, size_t in_len)
|
|
{
|
|
int state;
|
|
int ret = -1;
|
|
|
|
if (!sctx->type->pair_state_get)
|
|
{
|
|
sctx->errmsg = "Getting pair state unsupported";
|
|
return -1;
|
|
}
|
|
|
|
*out = NULL;
|
|
*out_len = 0;
|
|
|
|
state = sctx->type->pair_state_get(&sctx->errmsg, in, in_len);
|
|
if (state < 0)
|
|
return -1;
|
|
|
|
switch (state)
|
|
{
|
|
case 0:
|
|
*out = pair_setup_request1(out_len, sctx);
|
|
break;
|
|
case 1:
|
|
ret = pair_setup_response1(sctx, in, in_len);
|
|
if (ret < 0)
|
|
break;
|
|
*out = pair_setup_request1(out_len, sctx);
|
|
break;
|
|
case 2:
|
|
ret = pair_setup_response1(sctx, in, in_len);
|
|
if (ret < 0)
|
|
break;
|
|
*out = pair_setup_request2(out_len, sctx);
|
|
break;
|
|
case 3:
|
|
ret = pair_setup_response2(sctx, in, in_len);
|
|
if (ret < 0)
|
|
break;
|
|
*out = pair_setup_request2(out_len, sctx);
|
|
break;
|
|
case 4:
|
|
ret = pair_setup_response2(sctx, in, in_len);
|
|
if (ret < 0)
|
|
break;
|
|
*out = pair_setup_request3(out_len, sctx);
|
|
break;
|
|
case 5:
|
|
ret = pair_setup_response3(sctx, in, in_len);
|
|
if (ret < 0)
|
|
break;
|
|
*out = pair_setup_request3(out_len, sctx);
|
|
break;
|
|
case 6:
|
|
ret = pair_setup_response3(sctx, in, in_len);
|
|
if (ret < 0)
|
|
break;
|
|
break;
|
|
default:
|
|
sctx->errmsg = "Setup: Unsupported state";
|
|
ret = -1;
|
|
}
|
|
|
|
if (ret < 0 || !(*out))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint8_t *
|
|
pair_setup_request1(size_t *len, struct pair_setup_context *sctx)
|
|
{
|
|
if (!sctx->type->pair_setup_request1)
|
|
{
|
|
sctx->errmsg = "Setup request 1: Unsupported";
|
|
return NULL;
|
|
}
|
|
|
|
return sctx->type->pair_setup_request1(len, sctx);
|
|
}
|
|
|
|
uint8_t *
|
|
pair_setup_request2(size_t *len, struct pair_setup_context *sctx)
|
|
{
|
|
if (!sctx->type->pair_setup_request2)
|
|
{
|
|
sctx->errmsg = "Setup request 2: Unsupported";
|
|
return NULL;
|
|
}
|
|
|
|
return sctx->type->pair_setup_request2(len, sctx);
|
|
}
|
|
|
|
uint8_t *
|
|
pair_setup_request3(size_t *len, struct pair_setup_context *sctx)
|
|
{
|
|
if (!sctx->type->pair_setup_request3)
|
|
{
|
|
sctx->errmsg = "Setup request 3: Unsupported";
|
|
return NULL;
|
|
}
|
|
|
|
return sctx->type->pair_setup_request3(len, sctx);
|
|
}
|
|
|
|
int
|
|
pair_setup_response1(struct pair_setup_context *sctx, const uint8_t *in, size_t in_len)
|
|
{
|
|
if (!sctx->type->pair_setup_response1)
|
|
{
|
|
sctx->errmsg = "Setup response 1: Unsupported";
|
|
return -1;
|
|
}
|
|
|
|
return sctx->type->pair_setup_response1(sctx, in, in_len);
|
|
}
|
|
|
|
int
|
|
pair_setup_response2(struct pair_setup_context *sctx, const uint8_t *in, size_t in_len)
|
|
{
|
|
if (!sctx->type->pair_setup_response2)
|
|
{
|
|
sctx->errmsg = "Setup response 2: Unsupported";
|
|
return -1;
|
|
}
|
|
|
|
return sctx->type->pair_setup_response2(sctx, in, in_len);
|
|
}
|
|
|
|
int
|
|
pair_setup_response3(struct pair_setup_context *sctx, const uint8_t *in, size_t in_len)
|
|
{
|
|
if (!sctx->type->pair_setup_response3)
|
|
{
|
|
sctx->errmsg = "Setup response 3: Unsupported";
|
|
return -1;
|
|
}
|
|
|
|
if (sctx->type->pair_setup_response3(sctx, in, in_len) != 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pair_setup_result(const char **client_setup_keys, struct pair_result **result, struct pair_setup_context *sctx)
|
|
{
|
|
if (sctx->status != PAIR_STATUS_COMPLETED)
|
|
{
|
|
sctx->errmsg = "Setup result: Pair setup has not been completed";
|
|
return -1;
|
|
}
|
|
|
|
if (sctx->type->pair_setup_result)
|
|
{
|
|
if (sctx->type->pair_setup_result(sctx) != 0)
|
|
return -1;
|
|
}
|
|
|
|
if (client_setup_keys)
|
|
*client_setup_keys = sctx->result_str;
|
|
if (result)
|
|
*result = &sctx->result;
|
|
return 0;
|
|
}
|
|
|
|
struct pair_verify_context *
|
|
pair_verify_new(enum pair_type type, const char *client_setup_keys, pair_cb get_cb, void *cb_arg, const char *device_id)
|
|
{
|
|
struct pair_verify_context *vctx;
|
|
|
|
if (!pair[type]->pair_verify_new)
|
|
return NULL;
|
|
|
|
vctx = calloc(1, sizeof(struct pair_verify_context));
|
|
if (!vctx)
|
|
return NULL;
|
|
|
|
vctx->type = pair[type];
|
|
|
|
if (pair[type]->pair_verify_new(vctx, client_setup_keys, get_cb, cb_arg, device_id) < 0)
|
|
{
|
|
free(vctx);
|
|
return NULL;
|
|
}
|
|
|
|
return vctx;
|
|
}
|
|
|
|
void
|
|
pair_verify_free(struct pair_verify_context *vctx)
|
|
{
|
|
if (!vctx)
|
|
return;
|
|
|
|
if (vctx->type->pair_verify_free)
|
|
vctx->type->pair_verify_free(vctx);
|
|
|
|
free(vctx);
|
|
}
|
|
|
|
const char *
|
|
pair_verify_errmsg(struct pair_verify_context *vctx)
|
|
{
|
|
return vctx->errmsg;
|
|
}
|
|
|
|
int
|
|
pair_verify(uint8_t **out, size_t *out_len, struct pair_verify_context *vctx, const uint8_t *in, size_t in_len)
|
|
{
|
|
int state;
|
|
int ret = -1;
|
|
|
|
if (!vctx->type->pair_state_get)
|
|
{
|
|
vctx->errmsg = "Getting pair state unsupported";
|
|
return -1;
|
|
}
|
|
|
|
*out = NULL;
|
|
*out_len = 0;
|
|
|
|
state = vctx->type->pair_state_get(&vctx->errmsg, in, in_len);
|
|
if (state < 0)
|
|
return -1;
|
|
|
|
switch (state)
|
|
{
|
|
case 0:
|
|
*out = pair_verify_request1(out_len, vctx);
|
|
break;
|
|
case 1:
|
|
ret = pair_verify_response1(vctx, in, in_len);
|
|
if (ret < 0)
|
|
break;
|
|
*out = pair_verify_request1(out_len, vctx);
|
|
break;
|
|
case 2:
|
|
ret = pair_verify_response1(vctx, in, in_len);
|
|
if (ret < 0)
|
|
break;
|
|
*out = pair_verify_request2(out_len, vctx);
|
|
break;
|
|
case 3:
|
|
ret = pair_verify_response2(vctx, in, in_len);
|
|
if (ret < 0)
|
|
break;
|
|
*out = pair_verify_request2(out_len, vctx);
|
|
break;
|
|
case 4:
|
|
ret = pair_verify_response2(vctx, in, in_len);
|
|
if (ret < 0)
|
|
break;
|
|
break;
|
|
default:
|
|
vctx->errmsg = "Verify: Unsupported state";
|
|
ret = -1;
|
|
}
|
|
|
|
if (ret < 0 || !(*out))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint8_t *
|
|
pair_verify_request1(size_t *len, struct pair_verify_context *vctx)
|
|
{
|
|
if (!vctx->type->pair_verify_request1)
|
|
{
|
|
vctx->errmsg = "Verify request 1: Unsupported";
|
|
return NULL;
|
|
}
|
|
|
|
return vctx->type->pair_verify_request1(len, vctx);
|
|
}
|
|
|
|
uint8_t *
|
|
pair_verify_request2(size_t *len, struct pair_verify_context *vctx)
|
|
{
|
|
if (!vctx->type->pair_verify_request2)
|
|
{
|
|
vctx->errmsg = "Verify request 2: Unsupported";
|
|
return NULL;
|
|
}
|
|
|
|
return vctx->type->pair_verify_request2(len, vctx);
|
|
}
|
|
|
|
int
|
|
pair_verify_response1(struct pair_verify_context *vctx, const uint8_t *in, size_t in_len)
|
|
{
|
|
if (!vctx->type->pair_verify_response1)
|
|
{
|
|
vctx->errmsg = "Verify response 1: Unsupported";
|
|
return -1;
|
|
}
|
|
|
|
return vctx->type->pair_verify_response1(vctx, in, in_len);
|
|
}
|
|
|
|
int
|
|
pair_verify_response2(struct pair_verify_context *vctx, const uint8_t *in, size_t in_len)
|
|
{
|
|
if (!vctx->type->pair_verify_response2)
|
|
{
|
|
vctx->errmsg = "Verify response 2: Unsupported";
|
|
return -1;
|
|
}
|
|
|
|
if (vctx->type->pair_verify_response2(vctx, in, in_len) != 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pair_verify_result(struct pair_result **result, struct pair_verify_context *vctx)
|
|
{
|
|
if (vctx->status != PAIR_STATUS_COMPLETED)
|
|
{
|
|
vctx->errmsg = "Verify result: The pairing verification did not complete";
|
|
return -1;
|
|
}
|
|
|
|
if (vctx->type->pair_verify_result)
|
|
{
|
|
if (vctx->type->pair_verify_result(vctx) != 0)
|
|
return -1;
|
|
}
|
|
|
|
if (result)
|
|
*result = &vctx->result;
|
|
return 0;
|
|
}
|
|
|
|
struct pair_cipher_context *
|
|
pair_cipher_new(enum pair_type type, int channel, const uint8_t *shared_secret, size_t shared_secret_len)
|
|
{
|
|
if (!pair[type]->pair_cipher_new)
|
|
return NULL;
|
|
|
|
return pair[type]->pair_cipher_new(pair[type], channel, shared_secret, shared_secret_len);
|
|
}
|
|
|
|
void
|
|
pair_cipher_free(struct pair_cipher_context *cctx)
|
|
{
|
|
if (!cctx)
|
|
return;
|
|
|
|
if (!cctx->type->pair_cipher_free)
|
|
return;
|
|
|
|
return cctx->type->pair_cipher_free(cctx);
|
|
}
|
|
|
|
const char *
|
|
pair_cipher_errmsg(struct pair_cipher_context *cctx)
|
|
{
|
|
return cctx->errmsg;
|
|
}
|
|
|
|
ssize_t
|
|
pair_encrypt(uint8_t **ciphertext, size_t *ciphertext_len, const uint8_t *plaintext, size_t plaintext_len, struct pair_cipher_context *cctx)
|
|
{
|
|
if (!cctx->type->pair_encrypt)
|
|
{
|
|
cctx->errmsg = "Encryption unsupported";
|
|
return -1;
|
|
}
|
|
|
|
return cctx->type->pair_encrypt(ciphertext, ciphertext_len, plaintext, plaintext_len, 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)
|
|
{
|
|
if (!cctx->type->pair_decrypt)
|
|
{
|
|
cctx->errmsg = "Decryption unsupported";
|
|
return -1;
|
|
}
|
|
|
|
return cctx->type->pair_decrypt(plaintext, plaintext_len, ciphertext, ciphertext_len, cctx);
|
|
}
|
|
|
|
void
|
|
pair_encrypt_rollback(struct pair_cipher_context *cctx)
|
|
{
|
|
cctx->encryption_counter = cctx->encryption_counter_prev;
|
|
}
|
|
|
|
void
|
|
pair_decrypt_rollback(struct pair_cipher_context *cctx)
|
|
{
|
|
cctx->decryption_counter = cctx->decryption_counter_prev;
|
|
}
|
|
|
|
int
|
|
pair_add(enum pair_type type, uint8_t **out, size_t *out_len, pair_cb add_cb, void *cb_arg, const uint8_t *in, size_t in_len)
|
|
{
|
|
if (!pair[type]->pair_add)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return pair[type]->pair_add(out, out_len, add_cb, cb_arg, in, in_len);
|
|
}
|
|
|
|
int
|
|
pair_remove(enum pair_type type, uint8_t **out, size_t *out_len, pair_cb remove_cb, void *cb_arg, const uint8_t *in, size_t in_len)
|
|
{
|
|
if (!pair[type]->pair_remove)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return pair[type]->pair_remove(out, out_len, remove_cb, cb_arg, in, in_len);
|
|
}
|
|
|
|
int
|
|
pair_list(enum pair_type type, uint8_t **out, size_t *out_len, pair_list_cb list_cb, void *cb_arg, const uint8_t *in, size_t in_len)
|
|
{
|
|
if (!pair[type]->pair_list)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return pair[type]->pair_list(out, out_len, list_cb, cb_arg, in, in_len);
|
|
}
|
|
|
|
int
|
|
pair_state_get(enum pair_type type, const char **errmsg, const uint8_t *in, size_t in_len)
|
|
{
|
|
if (!pair[type]->pair_state_get)
|
|
{
|
|
*errmsg = "Getting pair state unsupported";
|
|
return -1;
|
|
}
|
|
|
|
return pair[type]->pair_state_get(errmsg, in, in_len);
|
|
}
|
|
|
|
void
|
|
pair_public_key_get(enum pair_type type, uint8_t server_public_key[32], const char *device_id)
|
|
{
|
|
if (!pair[type]->pair_public_key_get)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pair[type]->pair_public_key_get(server_public_key, device_id);
|
|
}
|