Merge pull request #2663 from cesanta/tls

TLS client implementation
This commit is contained in:
Sergio R. Caprile 2024-03-25 16:56:43 -03:00 committed by GitHub
commit d042697b10
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 6176 additions and 4564 deletions

View File

@ -15,8 +15,8 @@ jobs:
matrix:
cc: [gcc, clang++]
target: [test, mip_test]
ssl: ["", MBEDTLS]
name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }}}
ssl: ["", MBEDTLS, BUILTIN]
name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }}
env:
CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }}
@ -57,7 +57,7 @@ jobs:
strategy:
fail-fast: false
matrix:
ssl: ["", MBEDTLS]
ssl: ["", MBEDTLS, BUILTIN]
name: macos SSL=${{ matrix.ssl }}
env:
SSL: ${{ matrix.ssl }}

View File

@ -47,6 +47,10 @@ CFLAGS += -DMG_TLS=MG_TLS_OPENSSL -I$(OPENSSL)/include
LDFLAGS += -L$(OPENSSL)/lib -lssl -lcrypto
endif
ifeq "$(SSL)" "BUILTIN"
CFLAGS += -DMG_TLS=MG_TLS_BUILTIN
endif
all:
$(MAKE) -C examples/http-server
@ -75,9 +79,9 @@ examples_win:
clean_examples_win:
$(foreach X, $(EXAMPLES_WIN), $(MAKE) -C $(X) clean &)
test/packed_fs.c: Makefile src/ssi.h test/fuzz.c test/data/a.txt test/data/ca.pem
test/packed_fs.c: Makefile src/ssi.h test/fuzz.c test/data/a.txt test/data/ca.pem test/certs/ca.crt test/certs/server.crt test/certs/server.key
$(CC) $(CFLAGS) test/pack.c -o pack
$(RUN) ./pack Makefile src/ssi.h test/fuzz.c test/data/a.txt test/data/range.txt test/data/ca.pem > $@
$(RUN) ./pack Makefile src/ssi.h test/fuzz.c test/data/a.txt test/data/range.txt test/data/ca.pem test/certs/ca.crt test/certs/server.crt test/certs/server.key test/certs/client.key test/certs/client.crt > $@
# Check that all external (exported) symbols have "mg_" prefix
mg_prefix: mongoose.c mongoose.h
@ -184,7 +188,7 @@ mongoose.c: Makefile $(wildcard src/*.c) $(wildcard src/drivers/*.c)
(export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
mongoose.h: $(HDRS) Makefile
(cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/tls_aes128.h src/tls_uecc.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/device.h src/net_builtin.h src/profile.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
(cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/device.h src/net_builtin.h src/profile.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
clean: clean_examples clean_embedded

4535
mongoose.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ enum {
MG_PHY_KSZ8x_REG_PC2R = 31,
MG_PHY_LAN87x_REG_SCSR = 31,
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7
MG_PHY_RTL8201_REG_PAGESEL = 31,
MG_PHY_RTL8201_REG_PAGESEL = 31
};
static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
@ -39,11 +39,12 @@ static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
}
void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
uint16_t id1, id2;
phy->write_reg(phy_addr, MG_PHY_REG_BCR, MG_BIT(15)); // Reset PHY
phy->write_reg(phy_addr, MG_PHY_REG_BCR, MG_BIT(12)); // Autonegotiation
uint16_t id1 = phy->read_reg(phy_addr, MG_PHY_REG_ID1);
uint16_t id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2);
id1 = phy->read_reg(phy_addr, MG_PHY_REG_ID1);
id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2);
MG_INFO(("PHY ID: %#04x %#04x (%s)", id1, id2, mg_phy_id_to_str(id1, id2)));
if (config & MG_PHY_CLOCKS_MAC) {
@ -76,10 +77,11 @@ void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
bool mg_phy_up(struct mg_phy *phy, uint8_t phy_addr, bool *full_duplex,
uint8_t *speed) {
bool up = false;
uint16_t bsr = phy->read_reg(phy_addr, MG_PHY_REG_BSR);
if ((bsr & MG_BIT(5)) && !(bsr & MG_BIT(2))) // some PHYs latch down events
bsr = phy->read_reg(phy_addr, MG_PHY_REG_BSR); // read again
bool up = bsr & MG_BIT(2);
up = bsr & MG_BIT(2);
if (up && full_duplex != NULL && speed != NULL) {
uint16_t id1 = phy->read_reg(phy_addr, MG_PHY_REG_ID1);
if (id1 == MG_PHY_DP83x) {

View File

@ -12,7 +12,7 @@ enum {
MG_PHY_LEDS_ACTIVE_HIGH =
(1 << 0), // Set if PHY LEDs are connected to ground
MG_PHY_CLOCKS_MAC =
(1 << 1), // Set when PHY clocks MAC. Otherwise, MAC clocks PHY
(1 << 1) // Set when PHY clocks MAC. Otherwise, MAC clocks PHY
};
enum { MG_PHY_SPEED_10M, MG_PHY_SPEED_100M, MG_PHY_SPEED_1000M };

View File

@ -1,3 +1,9 @@
// https://github.com/B-Con/crypto-algorithms
// Author: Brad Conte (brad AT bradconte.com)
// Disclaimer: This code is presented "as is" without any guarantees.
// Details: Defines the API for the corresponding SHA1 implementation.
// Copyright: public domain
#include "sha256.h"
#define ror(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
@ -39,8 +45,10 @@ static void mg_sha256_chunk(mg_sha256_ctx *ctx) {
uint32_t a, b, c, d, e, f, g, h;
uint32_t m[64];
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = (uint32_t) ((ctx->buffer[j] << 24) | (ctx->buffer[j + 1] << 16) |
(ctx->buffer[j + 2] << 8) | (ctx->buffer[j + 3]));
m[i] = (uint32_t) (((uint32_t) ctx->buffer[j] << 24) |
((uint32_t) ctx->buffer[j + 1] << 16) |
((uint32_t) ctx->buffer[j + 2] << 8) |
((uint32_t) ctx->buffer[j + 3]));
for (; i < 64; ++i)
m[i] = sig1(m[i - 2]) + m[i - 7] + sig0(m[i - 15]) + m[i - 16];
@ -138,7 +146,7 @@ void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data,
memset(i_pad, 0x36, sizeof(i_pad));
memset(o_pad, 0x5c, sizeof(o_pad));
if (keysz < 64) {
memmove(k, key, keysz);
if (keysz > 0) memmove(k, key, keysz);
} else {
mg_sha256_init(&ctx);
mg_sha256_update(&ctx, key, keysz);
@ -157,4 +165,3 @@ void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data,
mg_sha256_update(&ctx, dst, 32);
mg_sha256_final(dst, &ctx);
}

View File

@ -1,3 +1,9 @@
// https://github.com/B-Con/crypto-algorithms
// Author: Brad Conte (brad AT bradconte.com)
// Disclaimer: This code is presented "as is" without any guarantees.
// Details: Defines the API for the corresponding SHA1 implementation.
// Copyright: public domain
#pragma once
#include "arch.h"

View File

@ -15,10 +15,11 @@
#include "tls_openssl.h"
struct mg_tls_opts {
struct mg_str ca; // PEM or DER
struct mg_str cert; // PEM or DER
struct mg_str key; // PEM or DER
struct mg_str name; // If not empty, enable host name verification
struct mg_str ca; // PEM or DER
struct mg_str cert; // PEM or DER
struct mg_str key; // PEM or DER
struct mg_str name; // If not empty, enable host name verification
int skip_verification; // Skip certificate and host name verification
};
void mg_tls_init(struct mg_connection *, const struct mg_tls_opts *opts);

View File

@ -20,10 +20,177 @@
*
*******************************************************************************/
#include "tls_aes128.h"
/******************************************************************************/
#define AES_DECRYPTION 1 // whether AES decryption is supported
/******************************************************************************/
#define MG_ENCRYPT 1 // specify whether we're encrypting
#define MG_DECRYPT 0 // or decrypting
#include "arch.h"
#include "tls.h"
#include "tls_aes128.h"
#if MG_TLS == MG_TLS_BUILTIN
/******************************************************************************
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
******************************************************************************/
static void aes_init_keygen_tables(void);
/******************************************************************************
* AES_SETKEY : called to expand the key for encryption or decryption
******************************************************************************/
static int aes_setkey(aes_context *ctx, // pointer to context
int mode, // 1 or 0 for Encrypt/Decrypt
const uchar *key, // AES input key
uint keysize); // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
// returns 0 for success
/******************************************************************************
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
******************************************************************************/
static int aes_cipher(aes_context *ctx, // pointer to context
const uchar input[16], // 128-bit block to en/decipher
uchar output[16]); // 128-bit output result block
// returns 0 for success
/******************************************************************************
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
******************************************************************************/
typedef struct {
int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length
uint64_t HL[16]; // precalculated lo-half HTable
uint64_t HH[16]; // precalculated hi-half HTable
uchar base_ectr[16]; // first counter-mode cipher output for tag
uchar y[16]; // the current cipher-input IV|Counter value
uchar buf[16]; // buf working value
aes_context aes_ctx; // cipher context used
} gcm_context;
/******************************************************************************
* GCM_SETKEY : sets the GCM (and AES) keying material for use
******************************************************************************/
static int gcm_setkey(
gcm_context *ctx, // caller-provided context ptr
const uchar *key, // pointer to cipher key
const uint keysize // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
); // returns 0 for success
/******************************************************************************
*
* GCM_CRYPT_AND_TAG
*
* This either encrypts or decrypts the user-provided data and, either
* way, generates an authentication tag of the requested length. It must be
* called with a GCM context whose key has already been set with GCM_SETKEY.
*
* The user would typically call this explicitly to ENCRYPT a buffer of data
* and optional associated data, and produce its an authentication tag.
*
* To reverse the process the user would typically call the companion
* GCM_AUTH_DECRYPT function to decrypt data and verify a user-provided
* authentication tag. The GCM_AUTH_DECRYPT function calls this function
* to perform its decryption and tag generation, which it then compares.
*
******************************************************************************/
static int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated
size_t tag_len); // byte length of the tag to be generated
/******************************************************************************
*
* GCM_START
*
* Given a user-provided GCM context, this initializes it, sets the encryption
* mode, and preprocesses the initialization vector and additional AEAD data.
*
******************************************************************************/
static int gcm_start(
gcm_context *ctx, // pointer to user-provided GCM context
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // pointer to additional AEAD data (NULL if none)
size_t add_len); // length of additional AEAD data (bytes)
/******************************************************************************
*
* GCM_UPDATE
*
* This is called once or more to process bulk plaintext or ciphertext data.
* We give this some number of bytes of input and it returns the same number
* of output bytes. If called multiple times (which is fine) all but the final
* invocation MUST be called with length mod 16 == 0. (Only the final call can
* have a partial block length of < 128 bits.)
*
******************************************************************************/
static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const uchar *input, // pointer to source data
uchar *output); // pointer to destination data
/******************************************************************************
*
* GCM_FINISH
*
* This is called once after all calls to GCM_UPDATE to finalize the GCM.
* It performs the final GHASH to produce the resulting authentication TAG.
*
******************************************************************************/
static int gcm_finish(
gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf
/******************************************************************************
*
* GCM_ZERO_CTX
*
* The GCM context contains both the GCM context and the AES context.
* This includes keying and key-related material which is security-
* sensitive, so it MUST be zeroed after use. This function does that.
*
******************************************************************************/
static void gcm_zero_ctx(gcm_context *ctx);
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
* of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly.
*
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#include "tls.h"
#include "tls_aes128.h"
static int aes_tables_inited = 0; // run-once flag for performing key
// expasion table generation (see below)
/*
@ -77,34 +244,34 @@ static uint32_t RCON[10]; // AES round constants
/*
* AES forward and reverse encryption round processing macros
*/
#define AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \
X0 = *RK++ ^ FT0[(Y0) &0xFF] ^ FT1[(Y1 >> 8) & 0xFF] ^ \
FT2[(Y2 >> 16) & 0xFF] ^ FT3[(Y3 >> 24) & 0xFF]; \
\
X1 = *RK++ ^ FT0[(Y1) &0xFF] ^ FT1[(Y2 >> 8) & 0xFF] ^ \
FT2[(Y3 >> 16) & 0xFF] ^ FT3[(Y0 >> 24) & 0xFF]; \
\
X2 = *RK++ ^ FT0[(Y2) &0xFF] ^ FT1[(Y3 >> 8) & 0xFF] ^ \
FT2[(Y0 >> 16) & 0xFF] ^ FT3[(Y1 >> 24) & 0xFF]; \
\
X3 = *RK++ ^ FT0[(Y3) &0xFF] ^ FT1[(Y0 >> 8) & 0xFF] ^ \
FT2[(Y1 >> 16) & 0xFF] ^ FT3[(Y2 >> 24) & 0xFF]; \
#define AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \
X0 = *RK++ ^ FT0[(Y0) & 0xFF] ^ FT1[(Y1 >> 8) & 0xFF] ^ \
FT2[(Y2 >> 16) & 0xFF] ^ FT3[(Y3 >> 24) & 0xFF]; \
\
X1 = *RK++ ^ FT0[(Y1) & 0xFF] ^ FT1[(Y2 >> 8) & 0xFF] ^ \
FT2[(Y3 >> 16) & 0xFF] ^ FT3[(Y0 >> 24) & 0xFF]; \
\
X2 = *RK++ ^ FT0[(Y2) & 0xFF] ^ FT1[(Y3 >> 8) & 0xFF] ^ \
FT2[(Y0 >> 16) & 0xFF] ^ FT3[(Y1 >> 24) & 0xFF]; \
\
X3 = *RK++ ^ FT0[(Y3) & 0xFF] ^ FT1[(Y0 >> 8) & 0xFF] ^ \
FT2[(Y1 >> 16) & 0xFF] ^ FT3[(Y2 >> 24) & 0xFF]; \
}
#define AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \
X0 = *RK++ ^ RT0[(Y0) &0xFF] ^ RT1[(Y3 >> 8) & 0xFF] ^ \
RT2[(Y2 >> 16) & 0xFF] ^ RT3[(Y1 >> 24) & 0xFF]; \
\
X1 = *RK++ ^ RT0[(Y1) &0xFF] ^ RT1[(Y0 >> 8) & 0xFF] ^ \
RT2[(Y3 >> 16) & 0xFF] ^ RT3[(Y2 >> 24) & 0xFF]; \
\
X2 = *RK++ ^ RT0[(Y2) &0xFF] ^ RT1[(Y1 >> 8) & 0xFF] ^ \
RT2[(Y0 >> 16) & 0xFF] ^ RT3[(Y3 >> 24) & 0xFF]; \
\
X3 = *RK++ ^ RT0[(Y3) &0xFF] ^ RT1[(Y2 >> 8) & 0xFF] ^ \
RT2[(Y1 >> 16) & 0xFF] ^ RT3[(Y0 >> 24) & 0xFF]; \
#define AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \
X0 = *RK++ ^ RT0[(Y0) & 0xFF] ^ RT1[(Y3 >> 8) & 0xFF] ^ \
RT2[(Y2 >> 16) & 0xFF] ^ RT3[(Y1 >> 24) & 0xFF]; \
\
X1 = *RK++ ^ RT0[(Y1) & 0xFF] ^ RT1[(Y0 >> 8) & 0xFF] ^ \
RT2[(Y3 >> 16) & 0xFF] ^ RT3[(Y2 >> 24) & 0xFF]; \
\
X2 = *RK++ ^ RT0[(Y2) & 0xFF] ^ RT1[(Y1 >> 8) & 0xFF] ^ \
RT2[(Y0 >> 16) & 0xFF] ^ RT3[(Y3 >> 24) & 0xFF]; \
\
X3 = *RK++ ^ RT0[(Y3) & 0xFF] ^ RT1[(Y2 >> 8) & 0xFF] ^ \
RT2[(Y1 >> 16) & 0xFF] ^ RT3[(Y0 >> 24) & 0xFF]; \
}
/*
@ -210,7 +377,8 @@ void aes_init_keygen_tables(void) {
* Valid lengths are: 16, 24 or 32 bytes (128, 192, 256 bits).
*
******************************************************************************/
static int aes_set_encryption_key(aes_context *ctx, const uchar *key, uint keysize) {
static int aes_set_encryption_key(aes_context *ctx, const uchar *key,
uint keysize) {
uint i; // general purpose iteration local
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
@ -287,7 +455,8 @@ static int aes_set_encryption_key(aes_context *ctx, const uchar *key, uint keysi
* length in bits. Valid lengths are: 128, 192, or 256 bits.
*
******************************************************************************/
static int aes_set_decryption_key(aes_context *ctx, const uchar *key, uint keysize) {
static int aes_set_decryption_key(aes_context *ctx, const uchar *key,
uint keysize) {
int i, j;
aes_context cty; // a calling aes context for set_encryption_key
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
@ -323,10 +492,10 @@ static int aes_set_decryption_key(aes_context *ctx, const uchar *key, uint keysi
* Invoked to establish the key schedule for subsequent encryption/decryption
*
******************************************************************************/
int aes_setkey(aes_context *ctx, // AES context provided by our caller
int mode, // ENCRYPT or DECRYPT flag
const uchar *key, // pointer to the key
uint keysize) // key length in bytes
static int aes_setkey(aes_context *ctx, // AES context provided by our caller
int mode, // ENCRYPT or DECRYPT flag
const uchar *key, // pointer to the key
uint keysize) // key length in bytes
{
// since table initialization is not thread safe, we could either add
// system-specific mutexes and init the AES key generation tables on
@ -369,7 +538,8 @@ int aes_setkey(aes_context *ctx, // AES context provided by our caller
* and all keying information appropriate for the task.
*
******************************************************************************/
int aes_cipher(aes_context *ctx, const uchar input[16], uchar output[16]) {
static int aes_cipher(aes_context *ctx, const uchar input[16],
uchar output[16]) {
int i;
uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals
@ -394,22 +564,22 @@ int aes_cipher(aes_context *ctx, const uchar input[16], uchar output[16]) {
AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
X0 = *RK++ ^ ((uint32_t) RSb[(Y0) &0xFF]) ^
X0 = *RK++ ^ ((uint32_t) RSb[(Y0) & 0xFF]) ^
((uint32_t) RSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t) RSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t) RSb[(Y1 >> 24) & 0xFF] << 24);
X1 = *RK++ ^ ((uint32_t) RSb[(Y1) &0xFF]) ^
X1 = *RK++ ^ ((uint32_t) RSb[(Y1) & 0xFF]) ^
((uint32_t) RSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t) RSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t) RSb[(Y2 >> 24) & 0xFF] << 24);
X2 = *RK++ ^ ((uint32_t) RSb[(Y2) &0xFF]) ^
X2 = *RK++ ^ ((uint32_t) RSb[(Y2) & 0xFF]) ^
((uint32_t) RSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t) RSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t) RSb[(Y3 >> 24) & 0xFF] << 24);
X3 = *RK++ ^ ((uint32_t) RSb[(Y3) &0xFF]) ^
X3 = *RK++ ^ ((uint32_t) RSb[(Y3) & 0xFF]) ^
((uint32_t) RSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t) RSb[(Y1 >> 16) & 0xFF] << 16) ^
((uint32_t) RSb[(Y0 >> 24) & 0xFF] << 24);
@ -424,22 +594,22 @@ int aes_cipher(aes_context *ctx, const uchar input[16], uchar output[16]) {
AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
X0 = *RK++ ^ ((uint32_t) FSb[(Y0) &0xFF]) ^
X0 = *RK++ ^ ((uint32_t) FSb[(Y0) & 0xFF]) ^
((uint32_t) FSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t) FSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t) FSb[(Y3 >> 24) & 0xFF] << 24);
X1 = *RK++ ^ ((uint32_t) FSb[(Y1) &0xFF]) ^
X1 = *RK++ ^ ((uint32_t) FSb[(Y1) & 0xFF]) ^
((uint32_t) FSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t) FSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t) FSb[(Y0 >> 24) & 0xFF] << 24);
X2 = *RK++ ^ ((uint32_t) FSb[(Y2) &0xFF]) ^
X2 = *RK++ ^ ((uint32_t) FSb[(Y2) & 0xFF]) ^
((uint32_t) FSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t) FSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t) FSb[(Y1 >> 24) & 0xFF] << 24);
X3 = *RK++ ^ ((uint32_t) FSb[(Y3) &0xFF]) ^
X3 = *RK++ ^ ((uint32_t) FSb[(Y3) & 0xFF]) ^
((uint32_t) FSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t) FSb[(Y1 >> 16) & 0xFF] << 16) ^
((uint32_t) FSb[(Y2 >> 24) & 0xFF] << 24);
@ -480,7 +650,6 @@ int aes_cipher(aes_context *ctx, const uchar input[16], uchar output[16]) {
*
*******************************************************************************/
/******************************************************************************
* ==== IMPLEMENTATION WARNING ====
*
@ -565,7 +734,7 @@ static const uint64_t last4[16] = {
* environment is running.
*
******************************************************************************/
int gcm_initialize(void) {
int mg_gcm_initialize(void) {
aes_init_keygen_tables();
return (0);
}
@ -625,10 +794,11 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
* and populates the gcm context's pre-calculated HTables.
*
******************************************************************************/
int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
const uchar *key, // pointer to the AES encryption key
const uint keysize) // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
static int gcm_setkey(
gcm_context *ctx, // pointer to caller-provided gcm context
const uchar *key, // pointer to the AES encryption key
const uint keysize) // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
{
int ret, i, j;
uint64_t hi, lo;
@ -717,7 +887,7 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
ctx->len = 0;
ctx->add_len = 0;
ctx->mode = mode; // set the GCM encryption/decryption mode
ctx->mode = mode; // set the GCM encryption/decryption mode
ctx->aes_ctx.mode = MG_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode
if (iv_len == 12) { // GCM natively uses a 12-byte, 96-bit IV
@ -895,51 +1065,6 @@ int gcm_crypt_and_tag(
return (0);
}
/******************************************************************************
*
* GCM_AUTH_DECRYPT
*
* This DECRYPTS a user-provided data buffer with optional associated data.
* It then verifies a user-supplied authentication tag against the tag just
* re-created during decryption to verify that the data has not been altered.
*
* This function calls GCM_CRYPT_AND_TAG (above) to perform the decryption
* and authentication tag generation.
*
******************************************************************************/
int gcm_auth_decrypt(
gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len) // byte length of the tag <= 16
{
uchar check_tag[16]; // the tag generated and returned by decryption
int diff; // an ORed flag to detect authentication errors
size_t i; // our local iterator
/*
we use GCM_DECRYPT_AND_TAG (above) to perform our decryption
(which is an identical XORing to reverse the previous one)
and also to re-generate the matching authentication tag
*/
gcm_crypt_and_tag(ctx, MG_DECRYPT, iv, iv_len, add, add_len, input, output,
length, check_tag, tag_len);
// now we verify the authentication tag in 'constant time'
for (diff = 0, i = 0; i < tag_len; i++) diff |= tag[i] ^ check_tag[i];
if (diff != 0) { // see whether any bits differed?
memset(output, 0, length); // if so... wipe the output data
return (GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
}
return (0);
}
/******************************************************************************
*
* GCM_ZERO_CTX
@ -961,29 +1086,29 @@ void gcm_zero_ctx(gcm_context *ctx) {
//
//
int aes_gcm_encrypt(unsigned char *output, //
const unsigned char *input, size_t input_length,
const unsigned char *key, const size_t key_len,
const unsigned char *iv, const size_t iv_len,
unsigned char *aead, size_t aead_len, unsigned char *tag,
const size_t tag_len) {
int mg_aes_gcm_encrypt(unsigned char *output, //
const unsigned char *input, size_t input_length,
const unsigned char *key, const size_t key_len,
const unsigned char *iv, const size_t iv_len,
unsigned char *aead, size_t aead_len, unsigned char *tag,
const size_t tag_len) {
int ret = 0; // our return value
gcm_context ctx; // includes the AES context structure
gcm_setkey(&ctx, key, (const uint) key_len);
ret = gcm_crypt_and_tag(&ctx, MG_ENCRYPT, iv, iv_len, aead, aead_len, input, output,
input_length, tag, tag_len);
ret = gcm_crypt_and_tag(&ctx, MG_ENCRYPT, iv, iv_len, aead, aead_len, input,
output, input_length, tag, tag_len);
gcm_zero_ctx(&ctx);
return (ret);
}
int aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv,
const size_t iv_len) {
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv,
const size_t iv_len) {
int ret = 0; // our return value
gcm_context ctx; // includes the AES context structure

View File

@ -1,74 +1,3 @@
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
* of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly.
*
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#ifndef AES_HEADER
#define AES_HEADER
/******************************************************************************/
#define AES_DECRYPTION 1 // whether AES decryption is supported
/******************************************************************************/
#define MG_ENCRYPT 1 // specify whether we're encrypting
#define MG_DECRYPT 0 // or decrypting
#include "arch.h"
typedef unsigned char uchar; // add some convienent shorter types
typedef unsigned int uint;
/******************************************************************************
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
******************************************************************************/
void aes_init_keygen_tables(void);
/******************************************************************************
* AES_CONTEXT : cipher context / holds inter-call data
******************************************************************************/
typedef struct {
int mode; // 1 for Encryption, 0 for Decryption
int rounds; // keysize-based rounds count
uint32_t *rk; // pointer to current round key
uint32_t buf[68]; // key expansion buffer
} aes_context;
/******************************************************************************
* AES_SETKEY : called to expand the key for encryption or decryption
******************************************************************************/
int aes_setkey(aes_context *ctx, // pointer to context
int mode, // 1 or 0 for Encrypt/Decrypt
const uchar *key, // AES input key
uint keysize); // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
// returns 0 for success
/******************************************************************************
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
******************************************************************************/
int aes_cipher(aes_context *ctx, // pointer to context
const uchar input[16], // 128-bit block to en/decipher
uchar output[16]); // 128-bit output result block
// returns 0 for success
#endif /* AES_HEADER */
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
@ -92,151 +21,30 @@ int aes_cipher(aes_context *ctx, // pointer to context
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#ifndef GCM_HEADER
#define GCM_HEADER
#ifndef TLS_AES128_H
#define TLS_AES128_H
typedef unsigned char uchar; // add some convienent shorter types
typedef unsigned int uint;
/******************************************************************************
* AES_CONTEXT : cipher context / holds inter-call data
******************************************************************************/
typedef struct {
int mode; // 1 for Encryption, 0 for Decryption
int rounds; // keysize-based rounds count
uint32_t *rk; // pointer to current round key
uint32_t buf[68]; // key expansion buffer
} aes_context;
#include "arch.h"
#define GCM_AUTH_FAILURE 0x55555555 // authentication failure
/******************************************************************************
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
******************************************************************************/
typedef struct {
int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length
uint64_t HL[16]; // precalculated lo-half HTable
uint64_t HH[16]; // precalculated hi-half HTable
uchar base_ectr[16]; // first counter-mode cipher output for tag
uchar y[16]; // the current cipher-input IV|Counter value
uchar buf[16]; // buf working value
aes_context aes_ctx; // cipher context used
} gcm_context;
/******************************************************************************
* GCM_CONTEXT : MUST be called once before ANY use of this library
******************************************************************************/
int gcm_initialize(void);
int mg_gcm_initialize(void);
/******************************************************************************
* GCM_SETKEY : sets the GCM (and AES) keying material for use
******************************************************************************/
int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
const uchar *key, // pointer to cipher key
const uint keysize // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
); // returns 0 for success
/******************************************************************************
*
* GCM_CRYPT_AND_TAG
*
* This either encrypts or decrypts the user-provided data and, either
* way, generates an authentication tag of the requested length. It must be
* called with a GCM context whose key has already been set with GCM_SETKEY.
*
* The user would typically call this explicitly to ENCRYPT a buffer of data
* and optional associated data, and produce its an authentication tag.
*
* To reverse the process the user would typically call the companion
* GCM_AUTH_DECRYPT function to decrypt data and verify a user-provided
* authentication tag. The GCM_AUTH_DECRYPT function calls this function
* to perform its decryption and tag generation, which it then compares.
*
******************************************************************************/
int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated
size_t tag_len); // byte length of the tag to be generated
/******************************************************************************
*
* GCM_AUTH_DECRYPT
*
* This DECRYPTS a user-provided data buffer with optional associated data.
* It then verifies a user-supplied authentication tag against the tag just
* re-created during decryption to verify that the data has not been altered.
*
* This function calls GCM_CRYPT_AND_TAG (above) to perform the decryption
* and authentication tag generation.
*
******************************************************************************/
int gcm_auth_decrypt(
gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len); // byte length of the tag <= 16
/******************************************************************************
*
* GCM_START
*
* Given a user-provided GCM context, this initializes it, sets the encryption
* mode, and preprocesses the initialization vector and additional AEAD data.
*
******************************************************************************/
int gcm_start(
gcm_context *ctx, // pointer to user-provided GCM context
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // pointer to additional AEAD data (NULL if none)
size_t add_len); // length of additional AEAD data (bytes)
/******************************************************************************
*
* GCM_UPDATE
*
* This is called once or more to process bulk plaintext or ciphertext data.
* We give this some number of bytes of input and it returns the same number
* of output bytes. If called multiple times (which is fine) all but the final
* invocation MUST be called with length mod 16 == 0. (Only the final call can
* have a partial block length of < 128 bits.)
*
******************************************************************************/
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const uchar *input, // pointer to source data
uchar *output); // pointer to destination data
/******************************************************************************
*
* GCM_FINISH
*
* This is called once after all calls to GCM_UPDATE to finalize the GCM.
* It performs the final GHASH to produce the resulting authentication TAG.
*
******************************************************************************/
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf
/******************************************************************************
*
* GCM_ZERO_CTX
*
* The GCM context contains both the GCM context and the AES context.
* This includes keying and key-related material which is security-
* sensitive, so it MUST be zeroed after use. This function does that.
*
******************************************************************************/
void gcm_zero_ctx(gcm_context *ctx);
#endif /* GCM_HEADER */
//
// aes-gcm.h
// MKo
@ -244,21 +52,18 @@ void gcm_zero_ctx(gcm_context *ctx);
// Created by Markus Kosmal on 20/11/14.
//
//
int mg_aes_gcm_encrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv,
const size_t iv_len, unsigned char *aead,
size_t aead_len, unsigned char *tag,
const size_t tag_len);
#ifndef mko_aes_gcm_h
#define mko_aes_gcm_h
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv,
const size_t iv_len);
int aes_gcm_encrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv,
const size_t iv_len, unsigned char *aead, size_t aead_len,
unsigned char *tag, const size_t tag_len);
int aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv,
const size_t iv_len);
#endif
#endif /* TLS_AES128_H */
// End of aes128 PD

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +1,46 @@
#pragma once
#include "arch.h"
#define uECC_SUPPORTS_secp256r1 1
#define MG_UECC_SUPPORTS_secp256r1 1
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_H_
#define _UECC_H_
/* Platform selection options.
If uECC_PLATFORM is not defined, the code will try to guess it based on compiler
macros. Possible values for uECC_PLATFORM are defined below: */
#define uECC_arch_other 0
#define uECC_x86 1
#define uECC_x86_64 2
#define uECC_arm 3
#define uECC_arm_thumb 4
#define uECC_arm_thumb2 5
#define uECC_arm64 6
#define uECC_avr 7
If MG_UECC_PLATFORM is not defined, the code will try to guess it based on
compiler macros. Possible values for MG_UECC_PLATFORM are defined below: */
#define mg_uecc_arch_other 0
#define mg_uecc_x86 1
#define mg_uecc_x86_64 2
#define mg_uecc_arm 3
#define mg_uecc_arm_thumb 4
#define mg_uecc_arm_thumb2 5
#define mg_uecc_arm64 6
#define mg_uecc_avr 7
/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform
(1, 4, or 8 bytes). If uECC_WORD_SIZE is not explicitly defined then it will be
automatically set based on your platform. */
/* If desired, you can define MG_UECC_WORD_SIZE as appropriate for your platform
(1, 4, or 8 bytes). If MG_UECC_WORD_SIZE is not explicitly defined then it will
be automatically set based on your platform. */
/* Optimization level; trade speed for code size.
Larger values produce code that is faster but larger.
Currently supported values are 0 - 4; 0 is unusably slow for most
applications. Optimization level 4 currently only has an effect ARM platforms
where more than one curve is enabled. */
#ifndef uECC_OPTIMIZATION_LEVEL
#define uECC_OPTIMIZATION_LEVEL 2
#ifndef MG_UECC_OPTIMIZATION_LEVEL
#define MG_UECC_OPTIMIZATION_LEVEL 2
#endif
/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a
/* MG_UECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a
specific function to be used for (scalar) squaring instead of the generic
multiplication function. This can make things faster somewhat faster, but
increases the code size. */
#ifndef uECC_SQUARE_FUNC
#define uECC_SQUARE_FUNC 0
#ifndef MG_UECC_SQUARE_FUNC
#define MG_UECC_SQUARE_FUNC 0
#endif
/* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will
/* MG_UECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will
switch to native little-endian format for *all* arrays passed in and out of the
public API. This includes public and private keys, shared secrets, signatures
and message hashes. Using this switch reduces the amount of call stack memory
@ -49,111 +49,112 @@ will *only* work on native little-endian processors and it will treat the
uint8_t arrays passed into the public API as word arrays, therefore requiring
the provided byte arrays to be word aligned on architectures that do not support
unaligned accesses. IMPORTANT: Keys and signatures generated with
uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible with keys and signatures
generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use the same
MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible with keys and signatures
generated with MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use the same
endianness. */
#ifndef uECC_VLI_NATIVE_LITTLE_ENDIAN
#define uECC_VLI_NATIVE_LITTLE_ENDIAN 0
#ifndef MG_UECC_VLI_NATIVE_LITTLE_ENDIAN
#define MG_UECC_VLI_NATIVE_LITTLE_ENDIAN 0
#endif
/* Curve support selection. Set to 0 to remove that curve. */
#ifndef uECC_SUPPORTS_secp160r1
#define uECC_SUPPORTS_secp160r1 0
#ifndef MG_UECC_SUPPORTS_secp160r1
#define MG_UECC_SUPPORTS_secp160r1 0
#endif
#ifndef uECC_SUPPORTS_secp192r1
#define uECC_SUPPORTS_secp192r1 0
#ifndef MG_UECC_SUPPORTS_secp192r1
#define MG_UECC_SUPPORTS_secp192r1 0
#endif
#ifndef uECC_SUPPORTS_secp224r1
#define uECC_SUPPORTS_secp224r1 0
#ifndef MG_UECC_SUPPORTS_secp224r1
#define MG_UECC_SUPPORTS_secp224r1 0
#endif
#ifndef uECC_SUPPORTS_secp256r1
#define uECC_SUPPORTS_secp256r1 1
#ifndef MG_UECC_SUPPORTS_secp256r1
#define MG_UECC_SUPPORTS_secp256r1 1
#endif
#ifndef uECC_SUPPORTS_secp256k1
#define uECC_SUPPORTS_secp256k1 0
#ifndef MG_UECC_SUPPORTS_secp256k1
#define MG_UECC_SUPPORTS_secp256k1 0
#endif
/* Specifies whether compressed point format is supported.
Set to 0 to disable point compression/decompression functions. */
#ifndef uECC_SUPPORT_COMPRESSED_POINT
#define uECC_SUPPORT_COMPRESSED_POINT 1
#ifndef MG_UECC_SUPPORT_COMPRESSED_POINT
#define MG_UECC_SUPPORT_COMPRESSED_POINT 1
#endif
struct uECC_Curve_t;
typedef const struct uECC_Curve_t *uECC_Curve;
struct MG_UECC_Curve_t;
typedef const struct MG_UECC_Curve_t *MG_UECC_Curve;
#ifdef __cplusplus
extern "C" {
#endif
#if uECC_SUPPORTS_secp160r1
uECC_Curve uECC_secp160r1(void);
#if MG_UECC_SUPPORTS_secp160r1
MG_UECC_Curve mg_uecc_secp160r1(void);
#endif
#if uECC_SUPPORTS_secp192r1
uECC_Curve uECC_secp192r1(void);
#if MG_UECC_SUPPORTS_secp192r1
MG_UECC_Curve mg_uecc_secp192r1(void);
#endif
#if uECC_SUPPORTS_secp224r1
uECC_Curve uECC_secp224r1(void);
#if MG_UECC_SUPPORTS_secp224r1
MG_UECC_Curve mg_uecc_secp224r1(void);
#endif
#if uECC_SUPPORTS_secp256r1
uECC_Curve uECC_secp256r1(void);
#if MG_UECC_SUPPORTS_secp256r1
MG_UECC_Curve mg_uecc_secp256r1(void);
#endif
#if uECC_SUPPORTS_secp256k1
uECC_Curve uECC_secp256k1(void);
#if MG_UECC_SUPPORTS_secp256k1
MG_UECC_Curve mg_uecc_secp256k1(void);
#endif
/* uECC_RNG_Function type
/* MG_UECC_RNG_Function type
The RNG function should fill 'size' random bytes into 'dest'. It should return 1
if 'dest' was filled with random data, or 0 if the random data could not be
generated. The filled-in values should be either truly random, or from a
cryptographically-secure PRNG.
A correctly functioning RNG function must be set (using uECC_set_rng()) before
calling uECC_make_key() or uECC_sign().
A correctly functioning RNG function must be set (using mg_uecc_set_rng())
before calling mg_uecc_make_key() or mg_uecc_sign().
Setting a correctly functioning RNG function improves the resistance to
side-channel attacks for uECC_shared_secret() and uECC_sign_deterministic().
side-channel attacks for mg_uecc_shared_secret() and
mg_uecc_sign_deterministic().
A correct RNG function is set by default when building for Windows, Linux, or OS
X. If you are building on another POSIX-compliant system that supports
/dev/random or /dev/urandom, you can define uECC_POSIX to use the predefined
/dev/random or /dev/urandom, you can define MG_UECC_POSIX to use the predefined
RNG. For embedded platforms there is no predefined RNG function; you must
provide your own.
*/
typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);
typedef int (*MG_UECC_RNG_Function)(uint8_t *dest, unsigned size);
/* uECC_set_rng() function.
/* mg_uecc_set_rng() function.
Set the function that will be used to generate random bytes. The RNG function
should return 1 if the random data was generated, or 0 if the random data could
not be generated.
On platforms where there is no predefined RNG function (eg embedded platforms),
this must be called before uECC_make_key() or uECC_sign() are used.
this must be called before mg_uecc_make_key() or mg_uecc_sign() are used.
Inputs:
rng_function - The function that will be used to generate random bytes.
*/
void uECC_set_rng(uECC_RNG_Function rng_function);
void mg_uecc_set_rng(MG_UECC_RNG_Function rng_function);
/* uECC_get_rng() function.
/* mg_uecc_get_rng() function.
Returns the function that will be used to generate random bytes.
*/
uECC_RNG_Function uECC_get_rng(void);
MG_UECC_RNG_Function mg_uecc_get_rng(void);
/* uECC_curve_private_key_size() function.
/* mg_uecc_curve_private_key_size() function.
Returns the size of a private key for the curve in bytes.
*/
int uECC_curve_private_key_size(uECC_Curve curve);
int mg_uecc_curve_private_key_size(MG_UECC_Curve curve);
/* uECC_curve_public_key_size() function.
/* mg_uecc_curve_public_key_size() function.
Returns the size of a public key for the curve in bytes.
*/
int uECC_curve_public_key_size(uECC_Curve curve);
int mg_uecc_curve_public_key_size(MG_UECC_Curve curve);
/* uECC_make_key() function.
/* mg_uecc_make_key() function.
Create a public/private key pair.
Outputs:
@ -170,14 +171,15 @@ being non-zero).
Returns 1 if the key pair was generated successfully, 0 if an error occurred.
*/
int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve);
int mg_uecc_make_key(uint8_t *public_key, uint8_t *private_key,
MG_UECC_Curve curve);
/* uECC_shared_secret() function.
/* mg_uecc_shared_secret() function.
Compute a shared secret given your secret key and someone else's public key. If
the public key is not from a trusted source and has not been previously
verified, you should verify it first using uECC_valid_public_key(). Note: It is
recommended that you hash the result of uECC_shared_secret() before using it for
symmetric encryption or HMAC.
verified, you should verify it first using mg_uecc_valid_public_key(). Note: It
is recommended that you hash the result of mg_uecc_shared_secret() before using
it for symmetric encryption or HMAC.
Inputs:
public_key - The public key of the remote party.
@ -191,11 +193,11 @@ size as the curve size; for example, if the curve is secp256r1, secret must be
Returns 1 if the shared secret was generated successfully, 0 if an error
occurred.
*/
int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key,
uint8_t *secret, uECC_Curve curve);
int mg_uecc_shared_secret(const uint8_t *public_key, const uint8_t *private_key,
uint8_t *secret, MG_UECC_Curve curve);
#if uECC_SUPPORT_COMPRESSED_POINT
/* uECC_compress() function.
#if MG_UECC_SUPPORT_COMPRESSED_POINT
/* mg_uecc_compress() function.
Compress a public key.
Inputs:
@ -206,10 +208,10 @@ Outputs:
least (curve size + 1) bytes long; for example, if the curve is secp256r1,
compressed must be 33 bytes long.
*/
void uECC_compress(const uint8_t *public_key, uint8_t *compressed,
uECC_Curve curve);
void mg_uecc_compress(const uint8_t *public_key, uint8_t *compressed,
MG_UECC_Curve curve);
/* uECC_decompress() function.
/* mg_uecc_decompress() function.
Decompress a compressed public key.
Inputs:
@ -218,11 +220,11 @@ Inputs:
Outputs:
public_key - Will be filled in with the decompressed public key.
*/
void uECC_decompress(const uint8_t *compressed, uint8_t *public_key,
uECC_Curve curve);
#endif /* uECC_SUPPORT_COMPRESSED_POINT */
void mg_uecc_decompress(const uint8_t *compressed, uint8_t *public_key,
MG_UECC_Curve curve);
#endif /* MG_UECC_SUPPORT_COMPRESSED_POINT */
/* uECC_valid_public_key() function.
/* mg_uecc_valid_public_key() function.
Check to see if a public key is valid.
Note that you are not required to check for a valid public key before using any
@ -234,9 +236,9 @@ Inputs:
Returns 1 if the public key is valid, 0 if it is invalid.
*/
int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve);
int mg_uecc_valid_public_key(const uint8_t *public_key, MG_UECC_Curve curve);
/* uECC_compute_public_key() function.
/* mg_uecc_compute_public_key() function.
Compute the corresponding public key for a private key.
Inputs:
@ -247,10 +249,10 @@ Outputs:
Returns 1 if the key was computed successfully, 0 if an error occurred.
*/
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key,
uECC_Curve curve);
int mg_uecc_compute_public_key(const uint8_t *private_key, uint8_t *public_key,
MG_UECC_Curve curve);
/* uECC_sign() function.
/* mg_uecc_sign() function.
Generate an ECDSA signature for a given hash value.
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and
@ -268,37 +270,37 @@ bytes long.
Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign(const uint8_t *private_key, const uint8_t *message_hash,
unsigned hash_size, uint8_t *signature, uECC_Curve curve);
int mg_uecc_sign(const uint8_t *private_key, const uint8_t *message_hash,
unsigned hash_size, uint8_t *signature, MG_UECC_Curve curve);
/* uECC_HashContext structure.
This is used to pass in an arbitrary hash function to uECC_sign_deterministic().
The structure will be used for multiple hash computations; each time a new hash
is computed, init_hash() will be called, followed by one or more calls to
update_hash(), and finally a call to finish_hash() to produce the resulting
hash.
/* MG_UECC_HashContext structure.
This is used to pass in an arbitrary hash function to
mg_uecc_sign_deterministic(). The structure will be used for multiple hash
computations; each time a new hash is computed, init_hash() will be called,
followed by one or more calls to update_hash(), and finally a call to
finish_hash() to produce the resulting hash.
The intention is that you will create a structure that includes uECC_HashContext
followed by any hash-specific data. For example:
The intention is that you will create a structure that includes
MG_UECC_HashContext followed by any hash-specific data. For example:
typedef struct SHA256_HashContext {
uECC_HashContext uECC;
MG_UECC_HashContext uECC;
SHA256_CTX ctx;
} SHA256_HashContext;
void init_SHA256(uECC_HashContext *base) {
void init_SHA256(MG_UECC_HashContext *base) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Init(&context->ctx);
}
void update_SHA256(uECC_HashContext *base,
void update_SHA256(MG_UECC_HashContext *base,
const uint8_t *message,
unsigned message_size) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Update(&context->ctx, message, message_size);
}
void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {
void finish_SHA256(MG_UECC_HashContext *base, uint8_t *hash_result) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Final(hash_result, &context->ctx);
}
@ -307,14 +309,14 @@ void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {
{
uint8_t tmp[32 + 32 + 64];
SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64,
32, tmp}}; uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature);
32, tmp}}; mg_uecc_sign_deterministic(key, message_hash, &ctx.uECC, signature);
}
*/
typedef struct uECC_HashContext {
void (*init_hash)(const struct uECC_HashContext *context);
void (*update_hash)(const struct uECC_HashContext *context,
typedef struct MG_UECC_HashContext {
void (*init_hash)(const struct MG_UECC_HashContext *context);
void (*update_hash)(const struct MG_UECC_HashContext *context,
const uint8_t *message, unsigned message_size);
void (*finish_hash)(const struct uECC_HashContext *context,
void (*finish_hash)(const struct MG_UECC_HashContext *context,
uint8_t *hash_result);
unsigned
block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
@ -322,11 +324,11 @@ typedef struct uECC_HashContext {
result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size +
block_size) bytes. */
} uECC_HashContext;
} MG_UECC_HashContext;
/* uECC_sign_deterministic() function.
/* mg_uecc_sign_deterministic() function.
Generate an ECDSA signature for a given hash value, using a deterministic
algorithm (see RFC 6979). You do not need to set the RNG using uECC_set_rng()
algorithm (see RFC 6979). You do not need to set the RNG using mg_uecc_set_rng()
before calling this function; however, if the RNG is defined it will improve
resistance to side-channel attacks.
@ -346,12 +348,12 @@ Outputs:
Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign_deterministic(const uint8_t *private_key,
const uint8_t *message_hash, unsigned hash_size,
const uECC_HashContext *hash_context,
uint8_t *signature, uECC_Curve curve);
int mg_uecc_sign_deterministic(const uint8_t *private_key,
const uint8_t *message_hash, unsigned hash_size,
const MG_UECC_HashContext *hash_context,
uint8_t *signature, MG_UECC_Curve curve);
/* uECC_verify() function.
/* mg_uecc_verify() function.
Verify an ECDSA signature.
Usage: Compute the hash of the signed data using the same hash as the signer and
@ -366,8 +368,9 @@ Inputs:
Returns 1 if the signature is valid, 0 if it is invalid.
*/
int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash,
unsigned hash_size, const uint8_t *signature, uECC_Curve curve);
int mg_uecc_verify(const uint8_t *public_key, const uint8_t *message_hash,
unsigned hash_size, const uint8_t *signature,
MG_UECC_Curve curve);
#ifdef __cplusplus
} /* end of extern "C" */
@ -380,153 +383,162 @@ int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash,
#ifndef _UECC_VLI_H_
#define _UECC_VLI_H_
//#include "types.h"
//#include "uECC.h"
// #include "types.h"
// #include "uECC.h"
/* Functions for raw large-integer manipulation. These are only available
if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */
#ifndef uECC_ENABLE_VLI_API
#define uECC_ENABLE_VLI_API 0
if uECC.c is compiled with MG_UECC_ENABLE_VLI_API defined to 1. */
#ifndef MG_UECC_ENABLE_VLI_API
#define MG_UECC_ENABLE_VLI_API 0
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if uECC_ENABLE_VLI_API
#if MG_UECC_ENABLE_VLI_API
void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words);
void mg_uecc_vli_clear(mg_uecc_word_t *vli, wordcount_t num_words);
/* Constant-time comparison to zero - secure way to compare long integers */
/* Returns 1 if vli == 0, 0 otherwise. */
uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words);
mg_uecc_word_t mg_uecc_vli_isZero(const mg_uecc_word_t *vli,
wordcount_t num_words);
/* Returns nonzero if bit 'bit' of vli is set. */
uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit);
mg_uecc_word_t mg_uecc_vli_testBit(const mg_uecc_word_t *vli, bitcount_t bit);
/* Counts the number of bits required to represent vli. */
bitcount_t uECC_vli_numBits(const uECC_word_t *vli,
const wordcount_t max_words);
bitcount_t mg_uecc_vli_numBits(const mg_uecc_word_t *vli,
const wordcount_t max_words);
/* Sets dest = src. */
void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src,
wordcount_t num_words);
void mg_uecc_vli_set(mg_uecc_word_t *dest, const mg_uecc_word_t *src,
wordcount_t num_words);
/* Constant-time comparison function - secure way to compare long integers */
/* Returns one if left == right, zero otherwise */
uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right,
wordcount_t num_words);
mg_uecc_word_t mg_uecc_vli_equal(const mg_uecc_word_t *left,
const mg_uecc_word_t *right,
wordcount_t num_words);
/* Constant-time comparison function - secure way to compare long integers */
/* Returns sign of left - right, in constant time. */
cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right,
wordcount_t num_words);
cmpresult_t mg_uecc_vli_cmp(const mg_uecc_word_t *left,
const mg_uecc_word_t *right, wordcount_t num_words);
/* Computes vli = vli >> 1. */
void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words);
void mg_uecc_vli_rshift1(mg_uecc_word_t *vli, wordcount_t num_words);
/* Computes result = left + right, returning carry. Can modify in place. */
uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, wordcount_t num_words);
mg_uecc_word_t mg_uecc_vli_add(mg_uecc_word_t *result,
const mg_uecc_word_t *left,
const mg_uecc_word_t *right,
wordcount_t num_words);
/* Computes result = left - right, returning borrow. Can modify in place. */
uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, wordcount_t num_words);
mg_uecc_word_t mg_uecc_vli_sub(mg_uecc_word_t *result,
const mg_uecc_word_t *left,
const mg_uecc_word_t *right,
wordcount_t num_words);
/* Computes result = left * right. Result must be 2 * num_words long. */
void uECC_vli_mult(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, wordcount_t num_words);
void mg_uecc_vli_mult(mg_uecc_word_t *result, const mg_uecc_word_t *left,
const mg_uecc_word_t *right, wordcount_t num_words);
/* Computes result = left^2. Result must be 2 * num_words long. */
void uECC_vli_square(uECC_word_t *result, const uECC_word_t *left,
wordcount_t num_words);
void mg_uecc_vli_square(mg_uecc_word_t *result, const mg_uecc_word_t *left,
wordcount_t num_words);
/* Computes result = (left + right) % mod.
Assumes that left < mod and right < mod, and that result does not overlap
mod. */
void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, const uECC_word_t *mod,
wordcount_t num_words);
void mg_uecc_vli_modAdd(mg_uecc_word_t *result, const mg_uecc_word_t *left,
const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
wordcount_t num_words);
/* Computes result = (left - right) % mod.
Assumes that left < mod and right < mod, and that result does not overlap
mod. */
void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, const uECC_word_t *mod,
wordcount_t num_words);
void mg_uecc_vli_modSub(mg_uecc_word_t *result, const mg_uecc_word_t *left,
const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
wordcount_t num_words);
/* Computes result = product % mod, where product is 2N words long.
Currently only designed to work for mod == curve->p or curve_n. */
void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
const uECC_word_t *mod, wordcount_t num_words);
void mg_uecc_vli_mmod(mg_uecc_word_t *result, mg_uecc_word_t *product,
const mg_uecc_word_t *mod, wordcount_t num_words);
/* Calculates result = product (mod curve->p), where product is up to
2 * curve->num_words long. */
void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product,
uECC_Curve curve);
void mg_uecc_vli_mmod_fast(mg_uecc_word_t *result, mg_uecc_word_t *product,
MG_UECC_Curve curve);
/* Computes result = (left * right) % mod.
Currently only designed to work for mod == curve->p or curve_n. */
void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, const uECC_word_t *mod,
wordcount_t num_words);
void mg_uecc_vli_modMult(mg_uecc_word_t *result, const mg_uecc_word_t *left,
const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
wordcount_t num_words);
/* Computes result = (left * right) % curve->p. */
void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, uECC_Curve curve);
void mg_uecc_vli_modMult_fast(mg_uecc_word_t *result,
const mg_uecc_word_t *left,
const mg_uecc_word_t *right, MG_UECC_Curve curve);
/* Computes result = left^2 % mod.
Currently only designed to work for mod == curve->p or curve_n. */
void uECC_vli_modSquare(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *mod, wordcount_t num_words);
void mg_uecc_vli_modSquare(mg_uecc_word_t *result, const mg_uecc_word_t *left,
const mg_uecc_word_t *mod, wordcount_t num_words);
/* Computes result = left^2 % curve->p. */
void uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left,
uECC_Curve curve);
void mg_uecc_vli_modSquare_fast(mg_uecc_word_t *result,
const mg_uecc_word_t *left,
MG_UECC_Curve curve);
/* Computes result = (1 / input) % mod.*/
void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
const uECC_word_t *mod, wordcount_t num_words);
void mg_uecc_vli_modInv(mg_uecc_word_t *result, const mg_uecc_word_t *input,
const mg_uecc_word_t *mod, wordcount_t num_words);
#if uECC_SUPPORT_COMPRESSED_POINT
#if MG_UECC_SUPPORT_COMPRESSED_POINT
/* Calculates a = sqrt(a) (mod curve->p) */
void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve);
void mg_uecc_vli_mod_sqrt(mg_uecc_word_t *a, MG_UECC_Curve curve);
#endif
/* Converts an integer in uECC native format to big-endian bytes. */
void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
const uECC_word_t *native);
void mg_uecc_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
const mg_uecc_word_t *native);
/* Converts big-endian bytes to an integer in uECC native format. */
void uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes,
int num_bytes);
void mg_uecc_vli_bytesToNative(mg_uecc_word_t *native, const uint8_t *bytes,
int num_bytes);
unsigned uECC_curve_num_words(uECC_Curve curve);
unsigned uECC_curve_num_bytes(uECC_Curve curve);
unsigned uECC_curve_num_bits(uECC_Curve curve);
unsigned uECC_curve_num_n_words(uECC_Curve curve);
unsigned uECC_curve_num_n_bytes(uECC_Curve curve);
unsigned uECC_curve_num_n_bits(uECC_Curve curve);
unsigned mg_uecc_curve_num_words(MG_UECC_Curve curve);
unsigned mg_uecc_curve_num_bytes(MG_UECC_Curve curve);
unsigned mg_uecc_curve_num_bits(MG_UECC_Curve curve);
unsigned mg_uecc_curve_num_n_words(MG_UECC_Curve curve);
unsigned mg_uecc_curve_num_n_bytes(MG_UECC_Curve curve);
unsigned mg_uecc_curve_num_n_bits(MG_UECC_Curve curve);
const uECC_word_t *uECC_curve_p(uECC_Curve curve);
const uECC_word_t *uECC_curve_n(uECC_Curve curve);
const uECC_word_t *uECC_curve_G(uECC_Curve curve);
const uECC_word_t *uECC_curve_b(uECC_Curve curve);
const mg_uecc_word_t *mg_uecc_curve_p(MG_UECC_Curve curve);
const mg_uecc_word_t *mg_uecc_curve_n(MG_UECC_Curve curve);
const mg_uecc_word_t *mg_uecc_curve_G(MG_UECC_Curve curve);
const mg_uecc_word_t *mg_uecc_curve_b(MG_UECC_Curve curve);
int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve);
int mg_uecc_valid_point(const mg_uecc_word_t *point, MG_UECC_Curve curve);
/* Multiplies a point by a scalar. Points are represented by the X coordinate
followed by the Y coordinate in the same array, both coordinates are
curve->num_words long. Note that scalar must be curve->num_n_words long (NOT
curve->num_words). */
void uECC_point_mult(uECC_word_t *result, const uECC_word_t *point,
const uECC_word_t *scalar, uECC_Curve curve);
void mg_uecc_point_mult(mg_uecc_word_t *result, const mg_uecc_word_t *point,
const mg_uecc_word_t *scalar, MG_UECC_Curve curve);
/* Generates a random integer in the range 0 < random < top.
Both random and top have num_words words. */
int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
wordcount_t num_words);
int mg_uecc_generate_random_int(mg_uecc_word_t *random,
const mg_uecc_word_t *top,
wordcount_t num_words);
#endif /* uECC_ENABLE_VLI_API */
#endif /* MG_UECC_ENABLE_VLI_API */
#ifdef __cplusplus
} /* end of extern "C" */
@ -539,101 +551,103 @@ int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
#ifndef _UECC_TYPES_H_
#define _UECC_TYPES_H_
#ifndef uECC_PLATFORM
#ifndef MG_UECC_PLATFORM
#if defined(__AVR__) && __AVR__
#define uECC_PLATFORM uECC_avr
#define MG_UECC_PLATFORM mg_uecc_avr
#elif defined(__thumb2__) || \
defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */
#define uECC_PLATFORM uECC_arm_thumb2
#define MG_UECC_PLATFORM mg_uecc_arm_thumb2
#elif defined(__thumb__)
#define uECC_PLATFORM uECC_arm_thumb
#define MG_UECC_PLATFORM mg_uecc_arm_thumb
#elif defined(__arm__) || defined(_M_ARM)
#define uECC_PLATFORM uECC_arm
#define MG_UECC_PLATFORM mg_uecc_arm
#elif defined(__aarch64__)
#define uECC_PLATFORM uECC_arm64
#define MG_UECC_PLATFORM mg_uecc_arm64
#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || \
defined(__I86__)
#define uECC_PLATFORM uECC_x86
#define MG_UECC_PLATFORM mg_uecc_x86
#elif defined(__amd64__) || defined(_M_X64)
#define uECC_PLATFORM uECC_x86_64
#define MG_UECC_PLATFORM mg_uecc_x86_64
#else
#define uECC_PLATFORM uECC_arch_other
#define MG_UECC_PLATFORM mg_uecc_arch_other
#endif
#endif
#ifndef uECC_ARM_USE_UMAAL
#if (uECC_PLATFORM == uECC_arm) && (__ARM_ARCH >= 6)
#define uECC_ARM_USE_UMAAL 1
#elif (uECC_PLATFORM == uECC_arm_thumb2) && (__ARM_ARCH >= 6) && \
#ifndef MG_UECC_ARM_USE_UMAAL
#if (MG_UECC_PLATFORM == mg_uecc_arm) && (__ARM_ARCH >= 6)
#define MG_UECC_ARM_USE_UMAAL 1
#elif (MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && (__ARM_ARCH >= 6) && \
(!defined(__ARM_ARCH_7M__) || !__ARM_ARCH_7M__)
#define uECC_ARM_USE_UMAAL 1
#define MG_UECC_ARM_USE_UMAAL 1
#else
#define uECC_ARM_USE_UMAAL 0
#define MG_UECC_ARM_USE_UMAAL 0
#endif
#endif
#ifndef uECC_WORD_SIZE
#if uECC_PLATFORM == uECC_avr
#define uECC_WORD_SIZE 1
#elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64)
#define uECC_WORD_SIZE 8
#ifndef MG_UECC_WORD_SIZE
#if MG_UECC_PLATFORM == mg_uecc_avr
#define MG_UECC_WORD_SIZE 1
#elif (MG_UECC_PLATFORM == mg_uecc_x86_64 || MG_UECC_PLATFORM == mg_uecc_arm64)
#define MG_UECC_WORD_SIZE 8
#else
#define uECC_WORD_SIZE 4
#define MG_UECC_WORD_SIZE 4
#endif
#endif
#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)
#error "Unsupported value for uECC_WORD_SIZE"
#if (MG_UECC_WORD_SIZE != 1) && (MG_UECC_WORD_SIZE != 4) && \
(MG_UECC_WORD_SIZE != 8)
#error "Unsupported value for MG_UECC_WORD_SIZE"
#endif
#if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))
#pragma message("uECC_WORD_SIZE must be 1 for AVR")
#undef uECC_WORD_SIZE
#define uECC_WORD_SIZE 1
#if ((MG_UECC_PLATFORM == mg_uecc_avr) && (MG_UECC_WORD_SIZE != 1))
#pragma message("MG_UECC_WORD_SIZE must be 1 for AVR")
#undef MG_UECC_WORD_SIZE
#define MG_UECC_WORD_SIZE 1
#endif
#if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
uECC_PLATFORM == uECC_arm_thumb2) && \
(uECC_WORD_SIZE != 4))
#pragma message("uECC_WORD_SIZE must be 4 for ARM")
#undef uECC_WORD_SIZE
#define uECC_WORD_SIZE 4
#if ((MG_UECC_PLATFORM == mg_uecc_arm || \
MG_UECC_PLATFORM == mg_uecc_arm_thumb || \
MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && \
(MG_UECC_WORD_SIZE != 4))
#pragma message("MG_UECC_WORD_SIZE must be 4 for ARM")
#undef MG_UECC_WORD_SIZE
#define MG_UECC_WORD_SIZE 4
#endif
typedef int8_t wordcount_t;
typedef int16_t bitcount_t;
typedef int8_t cmpresult_t;
#if (uECC_WORD_SIZE == 1)
#if (MG_UECC_WORD_SIZE == 1)
typedef uint8_t uECC_word_t;
typedef uint16_t uECC_dword_t;
typedef uint8_t mg_uecc_word_t;
typedef uint16_t mg_uecc_dword_t;
#define HIGH_BIT_SET 0x80
#define uECC_WORD_BITS 8
#define uECC_WORD_BITS_SHIFT 3
#define uECC_WORD_BITS_MASK 0x07
#define MG_UECC_WORD_BITS 8
#define MG_UECC_WORD_BITS_SHIFT 3
#define MG_UECC_WORD_BITS_MASK 0x07
#elif (uECC_WORD_SIZE == 4)
#elif (MG_UECC_WORD_SIZE == 4)
typedef uint32_t uECC_word_t;
typedef uint64_t uECC_dword_t;
typedef uint32_t mg_uecc_word_t;
typedef uint64_t mg_uecc_dword_t;
#define HIGH_BIT_SET 0x80000000
#define uECC_WORD_BITS 32
#define uECC_WORD_BITS_SHIFT 5
#define uECC_WORD_BITS_MASK 0x01F
#define MG_UECC_WORD_BITS 32
#define MG_UECC_WORD_BITS_SHIFT 5
#define MG_UECC_WORD_BITS_MASK 0x01F
#elif (uECC_WORD_SIZE == 8)
#elif (MG_UECC_WORD_SIZE == 8)
typedef uint64_t uECC_word_t;
typedef uint64_t mg_uecc_word_t;
#define HIGH_BIT_SET 0x8000000000000000U
#define uECC_WORD_BITS 64
#define uECC_WORD_BITS_SHIFT 6
#define uECC_WORD_BITS_MASK 0x03F
#define MG_UECC_WORD_BITS 64
#define MG_UECC_WORD_BITS_SHIFT 6
#define MG_UECC_WORD_BITS_MASK 0x03F
#endif /* uECC_WORD_SIZE */
#endif /* MG_UECC_WORD_SIZE */
#endif /* _UECC_TYPES_H_ */
// End of uecc BSD-2

246
src/tls_x25519.c Normal file
View File

@ -0,0 +1,246 @@
/**
* Adapted from STROBE: https://strobe.sourceforge.io/
* Copyright (c) 2015-2016 Cryptography Research, Inc.
* Author: Mike Hamburg
* License: MIT License
*/
#include "tls_x25519.h"
const uint8_t X25519_BASE_POINT[X25519_BYTES] = {9};
#define X25519_WBITS 32
typedef uint32_t limb_t;
typedef uint64_t dlimb_t;
typedef int64_t sdlimb_t;
#define LIMB(x) (uint32_t)(x##ull), (uint32_t) ((x##ull) >> 32)
#define NLIMBS (256 / X25519_WBITS)
typedef limb_t fe[NLIMBS];
static limb_t umaal(limb_t *carry, limb_t acc, limb_t mand, limb_t mier) {
dlimb_t tmp = (dlimb_t) mand * mier + acc + *carry;
*carry = (limb_t) (tmp >> X25519_WBITS);
return (limb_t) tmp;
}
// These functions are implemented in terms of umaal on ARM
static limb_t adc(limb_t *carry, limb_t acc, limb_t mand) {
dlimb_t total = (dlimb_t) *carry + acc + mand;
*carry = (limb_t) (total >> X25519_WBITS);
return (limb_t) total;
}
static limb_t adc0(limb_t *carry, limb_t acc) {
dlimb_t total = (dlimb_t) *carry + acc;
*carry = (limb_t) (total >> X25519_WBITS);
return (limb_t) total;
}
// - Precondition: carry is small.
// - Invariant: result of propagate is < 2^255 + 1 word
// - In particular, always less than 2p.
// - Also, output x >= min(x,19)
static void propagate(fe x, limb_t over) {
unsigned i;
limb_t carry;
over = x[NLIMBS - 1] >> (X25519_WBITS - 1) | over << 1;
x[NLIMBS - 1] &= ~((limb_t) 1 << (X25519_WBITS - 1));
carry = over * 19;
for (i = 0; i < NLIMBS; i++) {
x[i] = adc0(&carry, x[i]);
}
}
static void add(fe out, const fe a, const fe b) {
unsigned i;
limb_t carry = 0;
for (i = 0; i < NLIMBS; i++) {
out[i] = adc(&carry, a[i], b[i]);
}
propagate(out, carry);
}
static void sub(fe out, const fe a, const fe b) {
unsigned i;
sdlimb_t carry = -38;
for (i = 0; i < NLIMBS; i++) {
carry = carry + a[i] - b[i];
out[i] = (limb_t) carry;
carry >>= X25519_WBITS;
}
propagate(out, (limb_t) (1 + carry));
}
// `b` can contain less than 8 limbs, thus we use `limb_t *` instead of `fe`
// to avoid build warnings
static void mul(fe out, const fe a, const limb_t *b, unsigned nb) {
limb_t accum[2 * NLIMBS] = {0};
unsigned i, j;
limb_t carry2;
for (i = 0; i < nb; i++) {
limb_t mand = b[i];
carry2 = 0;
for (j = 0; j < NLIMBS; j++) {
limb_t tmp; // "a" may be misaligned
memcpy(&tmp, &a[j], sizeof(tmp)); // So make an aligned copy
accum[i + j] = umaal(&carry2, accum[i + j], mand, tmp);
}
accum[i + j] = carry2;
}
carry2 = 0;
for (j = 0; j < NLIMBS; j++) {
out[j] = umaal(&carry2, accum[j], 38, accum[j + NLIMBS]);
}
propagate(out, carry2);
}
static void sqr(fe out, const fe a) {
mul(out, a, a, NLIMBS);
}
static void mul1(fe out, const fe a) {
mul(out, a, out, NLIMBS);
}
static void sqr1(fe a) {
mul1(a, a);
}
static void condswap(limb_t a[2 * NLIMBS], limb_t b[2 * NLIMBS],
limb_t doswap) {
unsigned i;
for (i = 0; i < 2 * NLIMBS; i++) {
limb_t xor_ab = (a[i] ^ b[i]) & doswap;
a[i] ^= xor_ab;
b[i] ^= xor_ab;
}
}
// Canonicalize a field element x, reducing it to the least residue which is
// congruent to it mod 2^255-19
// - Precondition: x < 2^255 + 1 word
static limb_t canon(fe x) {
// First, add 19.
unsigned i;
limb_t carry0 = 19;
limb_t res;
sdlimb_t carry;
for (i = 0; i < NLIMBS; i++) {
x[i] = adc0(&carry0, x[i]);
}
propagate(x, carry0);
// Here, 19 <= x2 < 2^255
// - This is because we added 19, so before propagate it can't be less
// than 19. After propagate, it still can't be less than 19, because if
// propagate does anything it adds 19.
// - We know that the high bit must be clear, because either the input was ~
// 2^255 + one word + 19 (in which case it propagates to at most 2 words) or
// it was < 2^255. So now, if we subtract 19, we will get back to something in
// [0,2^255-19).
carry = -19;
res = 0;
for (i = 0; i < NLIMBS; i++) {
carry += x[i];
res |= x[i] = (limb_t) carry;
carry >>= X25519_WBITS;
}
return (limb_t) (((dlimb_t) res - 1) >> X25519_WBITS);
}
static const limb_t a24[1] = {121665};
static void ladder_part1(fe xs[5]) {
limb_t *x2 = xs[0], *z2 = xs[1], *x3 = xs[2], *z3 = xs[3], *t1 = xs[4];
add(t1, x2, z2); // t1 = A
sub(z2, x2, z2); // z2 = B
add(x2, x3, z3); // x2 = C
sub(z3, x3, z3); // z3 = D
mul1(z3, t1); // z3 = DA
mul1(x2, z2); // x3 = BC
add(x3, z3, x2); // x3 = DA+CB
sub(z3, z3, x2); // z3 = DA-CB
sqr1(t1); // t1 = AA
sqr1(z2); // z2 = BB
sub(x2, t1, z2); // x2 = E = AA-BB
mul(z2, x2, a24, sizeof(a24) / sizeof(a24[0])); // z2 = E*a24
add(z2, z2, t1); // z2 = E*a24 + AA
}
static void ladder_part2(fe xs[5], const fe x1) {
limb_t *x2 = xs[0], *z2 = xs[1], *x3 = xs[2], *z3 = xs[3], *t1 = xs[4];
sqr1(z3); // z3 = (DA-CB)^2
mul1(z3, x1); // z3 = x1 * (DA-CB)^2
sqr1(x3); // x3 = (DA+CB)^2
mul1(z2, x2); // z2 = AA*(E*a24+AA)
sub(x2, t1, x2); // x2 = BB again
mul1(x2, t1); // x2 = AA*BB
}
static void x25519_core(fe xs[5], const uint8_t scalar[X25519_BYTES],
const uint8_t *x1, int clamp) {
int i;
limb_t swap = 0;
limb_t *x2 = xs[0], *x3 = xs[2], *z3 = xs[3];
memset(xs, 0, 4 * sizeof(fe));
x2[0] = z3[0] = 1;
memcpy(x3, x1, sizeof(fe));
for (i = 255; i >= 0; i--) {
uint8_t bytei = scalar[i / 8];
limb_t doswap;
if (clamp) {
if (i / 8 == 0) {
bytei &= (uint8_t) ~7U;
} else if (i / 8 == X25519_BYTES - 1) {
bytei &= 0x7F;
bytei |= 0x40;
}
}
doswap = 0 - (limb_t) ((bytei >> (i % 8)) & 1);
condswap(x2, x3, swap ^ doswap);
swap = doswap;
ladder_part1(xs);
ladder_part2(xs, (const limb_t *) x1);
}
condswap(x2, x3, swap);
}
int mg_tls_x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES],
const uint8_t x1[X25519_BYTES], int clamp) {
int i, ret;
fe xs[5];
limb_t *x2, *z2, *z3, *prev;
static const struct {
uint8_t a, c, n;
} steps[13] = {{2, 1, 1}, {2, 1, 1}, {4, 2, 3}, {2, 4, 6}, {3, 1, 1},
{3, 2, 12}, {4, 3, 25}, {2, 3, 25}, {2, 4, 50}, {3, 2, 125},
{3, 1, 2}, {3, 1, 2}, {3, 1, 1}};
x25519_core(xs, scalar, x1, clamp);
// Precomputed inversion chain
x2 = xs[0];
z2 = xs[1];
z3 = xs[3];
prev = z2;
for (i = 0; i < 13; i++) {
int j;
limb_t *a = xs[steps[i].a];
for (j = steps[i].n; j > 0; j--) {
sqr(a, prev);
prev = a;
}
mul1(a, xs[steps[i].c]);
}
// Here prev = z3
// x2 /= z2
mul((limb_t *) out, x2, z3, NLIMBS);
ret = (int) canon((limb_t *) out);
if (!clamp) ret = 0;
return ret;
}

13
src/tls_x25519.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef TLS_X15519_H
#define TLS_X15519_H
#include "arch.h"
#define X25519_BYTES 32
extern const uint8_t X25519_BASE_POINT[X25519_BYTES];
int mg_tls_x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES],
const uint8_t x1[X25519_BYTES], int clamp);
#endif /* TLS_X15519_H */

8
test/certs/ca.crt Normal file
View File

@ -0,0 +1,8 @@
-----BEGIN CERTIFICATE-----
MIIBFTCBvAIJAJiASLWtAz5MMAoGCCqGSM49BAMCMBMxETAPBgNVBAMMCE1vbmdv
b3NlMB4XDTI0MDMyNTExNTU0NVoXDTM0MDMyMzExNTU0NVowEzERMA8GA1UEAwwI
TW9uZ29vc2UwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARaohnchUT4QTRIYKBX
1k0n3/PDwpXwiPyJIb+Wwfsmx0Y74KU7xGZLHK2C1PmIADVnTf3z304E97AXM+WV
3gkOMAoGCCqGSM49BAMCA0gAMEUCIQDJ0GYwCwucIKl+K/zRgptW6HVxD5y6+hu4
YBP9j+vwCAIgWJswYluq0szGxmfKnSXyTDioA1XrDhCVjYGO61U60Gk=
-----END CERTIFICATE-----

5
test/certs/ca.key Normal file
View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHtFV1AGKDqJRVBg3hQEmkHQDlXxCDFpIJ4b7UUyUtHRoAoGCCqGSM49
AwEHoUQDQgAEWqIZ3IVE+EE0SGCgV9ZNJ9/zw8KV8Ij8iSG/lsH7JsdGO+ClO8Rm
SxytgtT5iAA1Z039899OBPewFzPlld4JDg==
-----END EC PRIVATE KEY-----

1
test/certs/ca.srl Normal file
View File

@ -0,0 +1 @@
96EAA481EB95FF30

9
test/certs/client.crt Normal file
View File

@ -0,0 +1,9 @@
-----BEGIN CERTIFICATE-----
MIIBLTCB1KADAgECAgkAluqkgeuV/zAwCgYIKoZIzj0EAwIwEzERMA8GA1UEAwwI
TW9uZ29vc2UwHhcNMjQwMzI1MTE1NTQ1WhcNMjQwNDI0MTE1NTQ1WjAMMQowCAYD
VQQDDAFjMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoyB/9kTJJnPLlLFrQmME
6LMvCpjp05MuSTOvEmXqfWH+eC2e0bb6h7YIW+lcOrVQhDEt6xKFs1rqKUR0lgou
/6MYMBYwFAYDVR0RBA0wC4IJbG9jYWxob3N0MAoGCCqGSM49BAMCA0gAMEUCIQDy
11QWTyWuTq6avrsVi4lWfjMQSm14RxtyYUiStaahnwIgcXrf5MeOlupWLxPqEZTz
uOejUi45wZ6m3S1BLa31g3Y=
-----END CERTIFICATE-----

7
test/certs/client.csr Normal file
View File

@ -0,0 +1,7 @@
-----BEGIN CERTIFICATE REQUEST-----
MIHGMG4CAQAwDDEKMAgGA1UEAwwBYzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
BKMgf/ZEySZzy5Sxa0JjBOizLwqY6dOTLkkzrxJl6n1h/ngtntG2+oe2CFvpXDq1
UIQxLesShbNa6ilEdJYKLv+gADAKBggqhkjOPQQDAgNIADBFAiBDSG3wDIJaEn5c
PU+4WLGJ8+nzTewHGtpQELOXWURxLQIhAP5BocCQyrGW/5dEc/VWMgqH2eznZJcT
ftb9Tk6I6Pjx
-----END CERTIFICATE REQUEST-----

5
test/certs/client.key Normal file
View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIPEthf+Qq9dXJBxSZuYr2WhgzuhrDfMaD1kQzeKHZFfDoAoGCCqGSM49
AwEHoUQDQgAEoyB/9kTJJnPLlLFrQmME6LMvCpjp05MuSTOvEmXqfWH+eC2e0bb6
h7YIW+lcOrVQhDEt6xKFs1rqKUR0lgou/w==
-----END EC PRIVATE KEY-----

36
test/certs/generate.sh Normal file
View File

@ -0,0 +1,36 @@
#/bin/sh
#
# Geneate self-signed ECC certificates
cd `dirname $0`
# Create cnf for adding SAN DNS:localhost
# See https://security.stackexchange.com/questions/190905/subject-alternative-name-in-certificate-signing-request-apparently-does-not-surv
cat > cnf <<EOF
[SAN]
subjectAltName=DNS:localhost
EOF
# Generate CA
# Important: CN names must be different for CA and client/server certs
openssl ecparam -noout -name prime256v1 -genkey -out ca.key
openssl req -x509 -new -key ca.key -days 3650 -subj /CN=Mongoose -out ca.crt
# Generate server cert
openssl ecparam -noout -name prime256v1 -genkey -out server.key
openssl req -new -sha256 -key server.key -days 3650 -subj /CN=s -out server.csr
openssl x509 -req -sha256 -in server.csr -extensions SAN -extfile cnf \
-CAkey ca.key -CA ca.crt -CAcreateserial -out server.crt
# Generate client cert
openssl ecparam -noout -name prime256v1 -genkey -out client.key
openssl req -new -sha256 -key client.key -days 3650 -subj /CN=c -out client.csr
openssl x509 -req -sha256 -in client.csr -extensions SAN -extfile cnf \
-CAkey ca.key -CA ca.crt -CAcreateserial -out client.crt
# Verify
openssl verify -verbose -CAfile ca.crt server.crt
openssl verify -verbose -CAfile ca.crt client.crt
# Inspect
# openssl x509 -text -noout -ext subjectAltName -in server.crt

9
test/certs/server.crt Normal file
View File

@ -0,0 +1,9 @@
-----BEGIN CERTIFICATE-----
MIIBLTCB1KADAgECAgkAluqkgeuV/y8wCgYIKoZIzj0EAwIwEzERMA8GA1UEAwwI
TW9uZ29vc2UwHhcNMjQwMzI1MTE1NTQ1WhcNMjQwNDI0MTE1NTQ1WjAMMQowCAYD
VQQDDAFzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMExDcDCj1g8MeQrY+Ccy
voozGUcp7pi9M09q5GKYJ++WOEuEHDqnu4vEr/PQdgGhmeA5JmWEsztz1f0XgNuK
MaMYMBYwFAYDVR0RBA0wC4IJbG9jYWxob3N0MAoGCCqGSM49BAMCA0gAMEUCIQCn
K8fWr7ULIpU3Dq5IDm6NpNLd/fv4A5it0H0Un9noEAIgPdeWcFVsL7YrGfs0QkWV
y4ES/uFAj0jdQy8Vm+jzfD8=
-----END CERTIFICATE-----

7
test/certs/server.csr Normal file
View File

@ -0,0 +1,7 @@
-----BEGIN CERTIFICATE REQUEST-----
MIHFMG4CAQAwDDEKMAgGA1UEAwwBczBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
BDBMQ3Awo9YPDHkK2PgnMr6KMxlHKe6YvTNPauRimCfvljhLhBw6p7uLxK/z0HYB
oZngOSZlhLM7c9X9F4DbijGgADAKBggqhkjOPQQDAgNHADBEAiB4+PwVzRQn4dSE
I958FyxOJjKlKQ9DjBZCOStqrp2IugIgbAJG26EqDew7MvZWLtCR6ug6qBU2/hjG
0QDyaZrCHeQ=
-----END CERTIFICATE REQUEST-----

5
test/certs/server.key Normal file
View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFw94mvaH1YQyHWQRMNLU62csD8nu9GHJH5mKkiuJpPDoAoGCCqGSM49
AwEHoUQDQgAEMExDcDCj1g8MeQrY+CcyvoozGUcp7pi9M09q5GKYJ++WOEuEHDqn
u4vEr/PQdgGhmeA5JmWEsztz1f0XgNuKMQ==
-----END EC PRIVATE KEY-----

View File

@ -16,40 +16,6 @@ static int s_num_tests = 0;
#define FETCH_BUF_SIZE (256 * 1024)
// Self-signed CA, CERT, KEY
const char *s_tls_ca =
"-----BEGIN CERTIFICATE-----\n"
"MIIBqjCCAU+gAwIBAgIUESoOPGqMhf9uarzblVFwzrQweMcwCgYIKoZIzj0EAwIw\n"
"RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50\n"
"YTESMBAGA1UEAwwJVGVzdCBSb290MCAXDTIwMDUwOTIxNTE0NFoYDzIwNTAwNTA5\n"
"MjE1MTQ0WjBEMQswCQYDVQQGEwJJRTEPMA0GA1UEBwwGRHVibGluMRAwDgYDVQQK\n"
"DAdDZXNhbnRhMRIwEAYDVQQDDAlUZXN0IFJvb3QwWTATBgcqhkjOPQIBBggqhkjO\n"
"PQMBBwNCAAQsq9ECZiSW1xI+CVBP8VDuUehVA166sR2YsnJ5J6gbMQ1dUCH/QvLa\n"
"dBdeU7JlQcH8hN5KEbmM9BnZxMor6ussox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud\n"
"DwQEAwIBrjAKBggqhkjOPQQDAgNJADBGAiEAnHFsAIwGQQyRL81B04dH6d86Iq0l\n"
"fL8OKzndegxOaB0CIQCPwSIwEGFdURDqCC0CY2dnMrUGY5ZXu3hHCojZGS7zvg==\n"
"-----END CERTIFICATE-----\n";
const char *s_tls_cert =
"-----BEGIN CERTIFICATE-----\n"
"MIIBhzCCASygAwIBAgIUbnMoVd8TtWH1T09dANkK2LU6IUswCgYIKoZIzj0EAwIw\n"
"RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50\n"
"YTESMBAGA1UEAwwJVGVzdCBSb290MB4XDTIwMDUwOTIxNTE0OVoXDTMwMDUwOTIx\n"
"NTE0OVowETEPMA0GA1UEAwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n"
"QgAEkuBGnInDN6l06zVVQ1VcrOvH5FDu9MC6FwJc2e201P8hEpq0Q/SJS2nkbSuW\n"
"H/wBTTBaeXN2uhlBzMUWK790KKMvMC0wCQYDVR0TBAIwADALBgNVHQ8EBAMCA6gw\n"
"EwYDVR0lBAwwCgYIKwYBBQUHAwEwCgYIKoZIzj0EAwIDSQAwRgIhAPo6xx7LjCdZ\n"
"QY133XvLjAgVFrlucOZHONFVQuDXZsjwAiEAzHBNligA08c5U3SySYcnkhurGg50\n"
"BllCI0eYQ9ggp/o=\n"
"-----END CERTIFICATE-----\n";
const char *s_tls_key =
"-----BEGIN PRIVATE KEY-----\n"
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQglNni0t9Dg9icgG8w\n"
"kbfxWSS+TuNgbtNybIQXcm3NHpmhRANCAASS4EacicM3qXTrNVVDVVys68fkUO70\n"
"wLoXAlzZ7bTU/yESmrRD9IlLaeRtK5Yf/AFNMFp5c3a6GUHMxRYrv3Qo\n"
"-----END PRIVATE KEY-----\n";
// Important: we use different port numbers for the Windows bug workaround. See
// https://support.microsoft.com/en-ae/help/3039044/error-10013-wsaeacces-is-returned-when-a-second-bind-to-a-excluded-por
@ -743,10 +709,11 @@ static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
if (c != NULL && mg_url_is_ssl(url)) {
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
opts.name = mg_url_host(url);
opts.ca = mg_unpacked("/test/data/ca.pem");
if (strstr(url, "127.0.0.1") != NULL) {
if (strstr(url, "localhost") != NULL) {
// Local connection, use self-signed certificates
opts.ca = mg_str(s_tls_ca);
opts.ca = mg_unpacked("/test/certs/ca.crt");
// opts.cert = mg_str(s_tls_cert);
// opts.key = mg_str(s_tls_key);
}
@ -1207,14 +1174,14 @@ static void test_tls(void) {
#if MG_TLS
struct mg_mgr mgr;
struct mg_connection *c;
const char *url = "https://127.0.0.1:12347";
const char *url = "https://localhost:12347";
char buf[FETCH_BUF_SIZE];
struct mg_tls_opts opts;
struct mg_str data = mg_unpacked("/Makefile");
memset(&opts, 0, sizeof(opts));
// opts.ca = mg_str(s_tls_ca);
opts.cert = mg_str(s_tls_cert);
opts.key = mg_str(s_tls_key);
opts.cert = mg_unpacked("/test/certs/server.crt");
opts.key = mg_unpacked("/test/certs/server.key");
mg_mgr_init(&mgr);
c = mg_http_listen(&mgr, url, eh1, &opts);
ASSERT(c != NULL);
@ -1334,6 +1301,7 @@ static void test_host_validation(void) {
c = mg_http_connect(&mgr, url, f3, &ok);
ASSERT(c != NULL);
opts.ca = mg_unpacked("/test/data/ca.pem");
opts.name = mg_url_host(url);
mg_tls_init(c, &opts);
for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
ASSERT(ok == 200);