Merge ^/head r344549 through r344775.

This commit is contained in:
Dimitry Andric 2019-03-04 19:14:32 +00:00
commit 844fc3e907
1627 changed files with 151490 additions and 17701 deletions

View File

@ -106,7 +106,12 @@ usr.sbin/bsdconfig dteske Pre-commit phabricator review requested.
usr.sbin/dpv dteske Pre-commit review requested. Keep in sync with libdpv.
usr.sbin/pkg pkg@ Please coordinate behavior or flag changes with pkg team.
usr.sbin/sysrc dteske Pre-commit phabricator review requested. Keep in sync with bsdconfig(8) sysrc.subr.
vmm(4) tychon, jhb Pre-commit review requested.
vmm(4) tychon, jhb Pre-commit review requested via #bhyve
phabricator group.
libvmmapi tychon, jhb Pre-commit review requested via #bhyve
phabricator group.
usr.sbin/bhyve* tychon, jhb Pre-commit review requested via #bhyve
phabricator group.
autofs(5) trasz Pre-commit review recommended.
iscsi(4) trasz Pre-commit review recommended.
rctl(8) trasz Pre-commit review recommended.

View File

@ -190,9 +190,11 @@ OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_
OLD_DIRS+=usr/lib/clang/7.0.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/7.0.1/lib
OLD_DIRS+=usr/lib/clang/7.0.1
# 20190227: rename seq.h to seqc.h
OLD_FILES+=usr/include/sys/seq.h
# 20190222: libifconfig made INTERNALLIB
OLD_FILES+=/usr/lib/libprivateifconfig.a
OLD_FILES+=/usr/lib/libprivateifconfig_p.a
OLD_FILES+=usr/lib/libprivateifconfig.a
OLD_FILES+=usr/lib/libprivateifconfig_p.a
# 20190131: pfil(9) changed
OLD_FILES+=usr/share/man/man9/pfil_hook_get.9
OLD_FILES+=usr/share/man/man9/pfil_rlock.9

View File

@ -32,7 +32,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd August 11, 2018
.Dd February 15, 2018
.Dt ZFS 8
.Os
.Sh NAME
@ -184,7 +184,7 @@
.Ar bookmark
.Nm
.Cm send
.Op Fl DLPRcenpv
.Op Fl DLPRVcenpv
.Op Fl i Ar snapshot | Fl I Ar snapshot
.Ar snapshot
.Nm
@ -194,7 +194,7 @@
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
.Nm
.Cm send
.Op Fl Penv
.Op Fl PVenv
.Fl t Ar receive_resume_token
.Nm
.Cm receive Ns | Ns Cm recv
@ -2607,7 +2607,7 @@ feature.
.It Xo
.Nm
.Cm send
.Op Fl DLPRcenpv
.Op Fl DLPRVcenpv
.Op Fl i Ar snapshot | Fl I Ar snapshot
.Ar snapshot
.Xc
@ -2753,6 +2753,8 @@ Print machine-parsable verbose information about the stream package generated.
.It Fl v, -verbose
Print verbose information about the stream package generated.
This information includes a per-second report of how much data has been sent.
.It Fl V
Set the process title to a per-second report of how much data has been sent.
.El
.Pp
The format of the stream is committed. You will be able to receive your streams

View File

@ -3813,7 +3813,7 @@ zfs_do_send(int argc, char **argv)
};
/* check options */
while ((c = getopt_long(argc, argv, ":i:I:RbDpvnPLet:c", long_options,
while ((c = getopt_long(argc, argv, ":i:I:RbDpVvnPLet:c", long_options,
NULL)) != -1) {
switch (c) {
case 'i':
@ -3837,6 +3837,10 @@ zfs_do_send(int argc, char **argv)
flags.parsable = B_TRUE;
flags.verbose = B_TRUE;
break;
case 'V':
flags.progress = B_TRUE;
flags.progressastitle = B_TRUE;
break;
case 'v':
if (flags.verbose)
extraverbose = B_TRUE;
@ -5812,7 +5816,12 @@ zfs_do_holds(int argc, char **argv)
#define CHECK_SPINNER 30
#define SPINNER_TIME 3 /* seconds */
#define MOUNT_TIME 5 /* seconds */
#define MOUNT_TIME 1 /* seconds */
typedef struct get_all_state {
boolean_t ga_verbose;
get_all_cb_t *ga_cbp;
} get_all_state_t;
static int
get_one_dataset(zfs_handle_t *zhp, void *data)
@ -5821,10 +5830,10 @@ get_one_dataset(zfs_handle_t *zhp, void *data)
static int spinval = 0;
static int spincheck = 0;
static time_t last_spin_time = (time_t)0;
get_all_cb_t *cbp = data;
get_all_state_t *state = data;
zfs_type_t type = zfs_get_type(zhp);
if (cbp->cb_verbose) {
if (state->ga_verbose) {
if (--spincheck < 0) {
time_t now = time(NULL);
if (last_spin_time + SPINNER_TIME < now) {
@ -5850,25 +5859,23 @@ get_one_dataset(zfs_handle_t *zhp, void *data)
zfs_close(zhp);
return (0);
}
libzfs_add_handle(cbp, zhp);
assert(cbp->cb_used <= cbp->cb_alloc);
libzfs_add_handle(state->ga_cbp, zhp);
assert(state->ga_cbp->cb_used <= state->ga_cbp->cb_alloc);
return (0);
}
static void
get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose)
get_all_datasets(get_all_cb_t *cbp, boolean_t verbose)
{
get_all_cb_t cb = { 0 };
cb.cb_verbose = verbose;
cb.cb_getone = get_one_dataset;
get_all_state_t state = {
.ga_verbose = verbose,
.ga_cbp = cbp
};
if (verbose)
set_progress_header(gettext("Reading ZFS config"));
(void) zfs_iter_root(g_zfs, get_one_dataset, &cb);
*dslist = cb.cb_handles;
*count = cb.cb_used;
(void) zfs_iter_root(g_zfs, get_one_dataset, &state);
if (verbose)
finish_progress(gettext("done."));
@ -5879,8 +5886,19 @@ get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose)
* similar, we have a common function with an extra parameter to determine which
* mode we are using.
*/
#define OP_SHARE 0x1
#define OP_MOUNT 0x2
typedef enum { OP_SHARE, OP_MOUNT } share_mount_op_t;
typedef struct share_mount_state {
share_mount_op_t sm_op;
boolean_t sm_verbose;
int sm_flags;
char *sm_options;
char *sm_proto; /* only valid for OP_SHARE */
pthread_mutex_t sm_lock; /* protects the remaining fields */
uint_t sm_total; /* number of filesystems to process */
uint_t sm_done; /* number of filesystems processed */
int sm_status; /* -1 if any of the share/mount operations failed */
} share_mount_state_t;
/*
* Share or mount a dataset.
@ -6101,9 +6119,6 @@ report_mount_progress(int current, int total)
time_t now = time(NULL);
char info[32];
/* report 1..n instead of 0..n-1 */
++current;
/* display header if we're here for the first time */
if (current == 1) {
set_progress_header(gettext("Mounting ZFS filesystems"));
@ -6122,6 +6137,29 @@ report_mount_progress(int current, int total)
update_progress(info);
}
/*
* zfs_foreach_mountpoint() callback that mounts or shares on filesystem and
* updates the progress meter
*/
static int
share_mount_one_cb(zfs_handle_t *zhp, void *arg)
{
share_mount_state_t *sms = arg;
int ret;
ret = share_mount_one(zhp, sms->sm_op, sms->sm_flags, sms->sm_proto,
B_FALSE, sms->sm_options);
pthread_mutex_lock(&sms->sm_lock);
if (ret != 0)
sms->sm_status = ret;
sms->sm_done++;
if (sms->sm_verbose)
report_mount_progress(sms->sm_done, sms->sm_total);
pthread_mutex_unlock(&sms->sm_lock);
return (ret);
}
static void
append_options(char *mntopts, char *newopts)
{
@ -6194,8 +6232,6 @@ share_mount(int op, int argc, char **argv)
/* check number of arguments */
if (do_all) {
zfs_handle_t **dslist = NULL;
size_t i, count = 0;
char *protocol = NULL;
if (op == OP_SHARE && argc > 0) {
@ -6216,35 +6252,48 @@ share_mount(int op, int argc, char **argv)
}
start_progress_timer();
get_all_datasets(&dslist, &count, verbose);
get_all_cb_t cb = { 0 };
get_all_datasets(&cb, verbose);
if (count == 0)
if (cb.cb_used == 0) {
if (options != NULL)
free(options);
return (0);
}
qsort(dslist, count, sizeof (void *), libzfs_dataset_cmp);
#ifdef illumos
sa_init_selective_arg_t sharearg;
sharearg.zhandle_arr = dslist;
sharearg.zhandle_len = count;
if ((ret = zfs_init_libshare_arg(zfs_get_handle(dslist[0]),
SA_INIT_SHARE_API_SELECTIVE, &sharearg)) != SA_OK) {
(void) fprintf(stderr,
gettext("Could not initialize libshare, %d"), ret);
return (ret);
if (op == OP_SHARE) {
sa_init_selective_arg_t sharearg;
sharearg.zhandle_arr = cb.cb_handles;
sharearg.zhandle_len = cb.cb_used;
if ((ret = zfs_init_libshare_arg(g_zfs,
SA_INIT_SHARE_API_SELECTIVE, &sharearg)) != SA_OK) {
(void) fprintf(stderr, gettext(
"Could not initialize libshare, %d"), ret);
return (ret);
}
}
#endif
share_mount_state_t share_mount_state = { 0 };
share_mount_state.sm_op = op;
share_mount_state.sm_verbose = verbose;
share_mount_state.sm_flags = flags;
share_mount_state.sm_options = options;
share_mount_state.sm_proto = protocol;
share_mount_state.sm_total = cb.cb_used;
pthread_mutex_init(&share_mount_state.sm_lock, NULL);
for (i = 0; i < count; i++) {
if (verbose)
report_mount_progress(i, count);
/*
* libshare isn't mt-safe, so only do the operation in parallel
* if we're mounting.
*/
zfs_foreach_mountpoint(g_zfs, cb.cb_handles, cb.cb_used,
share_mount_one_cb, &share_mount_state, op == OP_MOUNT);
ret = share_mount_state.sm_status;
if (share_mount_one(dslist[i], op, flags, protocol,
B_FALSE, options) != 0)
ret = 1;
zfs_close(dslist[i]);
}
free(dslist);
for (int i = 0; i < cb.cb_used; i++)
zfs_close(cb.cb_handles[i]);
free(cb.cb_handles);
} else if (argc == 0) {
struct mnttab entry;

View File

@ -579,12 +579,12 @@ typedef struct get_all_cb {
zfs_handle_t **cb_handles;
size_t cb_alloc;
size_t cb_used;
boolean_t cb_verbose;
int (*cb_getone)(zfs_handle_t *, void *);
} get_all_cb_t;
void zfs_foreach_mountpoint(libzfs_handle_t *, zfs_handle_t **, size_t,
zfs_iter_f, void*, boolean_t);
void libzfs_add_handle(get_all_cb_t *, zfs_handle_t *);
int libzfs_dataset_cmp(const void *, const void *);
/*
* Functions to create and destroy datasets.
@ -651,6 +651,9 @@ typedef struct sendflags {
/* compressed WRITE records are permitted */
boolean_t compress;
/* show progress as process title(ie. -V) */
boolean_t progressastitle;
} sendflags_t;
typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);

View File

@ -799,6 +799,7 @@ libzfs_mnttab_cache_compare(const void *arg1, const void *arg2)
void
libzfs_mnttab_init(libzfs_handle_t *hdl)
{
pthread_mutex_init(&hdl->libzfs_mnttab_cache_lock, NULL);
assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0);
avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare,
sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
@ -839,6 +840,7 @@ libzfs_mnttab_fini(libzfs_handle_t *hdl)
free(mtn);
}
avl_destroy(&hdl->libzfs_mnttab_cache);
(void) pthread_mutex_destroy(&hdl->libzfs_mnttab_cache_lock);
}
void
@ -853,6 +855,7 @@ libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
{
mnttab_node_t find;
mnttab_node_t *mtn;
int ret = ENOENT;
if (!hdl->libzfs_mnttab_enable) {
struct mnttab srch = { 0 };
@ -868,6 +871,7 @@ libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
return (ENOENT);
}
pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock);
if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
libzfs_mnttab_update(hdl);
@ -875,9 +879,10 @@ libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL);
if (mtn) {
*entry = mtn->mtn_mt;
return (0);
ret = 0;
}
return (ENOENT);
pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock);
return (ret);
}
void
@ -886,15 +891,17 @@ libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
{
mnttab_node_t *mtn;
if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
return;
mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
avl_add(&hdl->libzfs_mnttab_cache, mtn);
}
pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock);
if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) {
mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
avl_add(&hdl->libzfs_mnttab_cache, mtn);
}
pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock);
}
void
libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
@ -902,6 +909,7 @@ libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
mnttab_node_t find;
mnttab_node_t *ret;
pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock);
find.mtn_mt.mnt_special = (char *)fsname;
if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL))
!= NULL) {
@ -912,6 +920,7 @@ libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
free(ret->mtn_mt.mnt_mntopts);
free(ret);
}
pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock);
}
int

View File

@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved.
* Copyright (c) 2011, 2016 by Delphix. All rights reserved.
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
* Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
@ -73,6 +73,13 @@ struct libzfs_handle {
int libzfs_storeerr; /* stuff error messages into buffer */
void *libzfs_sharehdl; /* libshare handle */
boolean_t libzfs_mnttab_enable;
/*
* We need a lock to handle the case where parallel mount
* threads are populating the mnttab cache simultaneously. The
* lock only protects the integrity of the avl tree, and does
* not protect the contents of the mnttab entries themselves.
*/
pthread_mutex_t libzfs_mnttab_cache_lock;
avl_tree_t libzfs_mnttab_cache;
int libzfs_pool_iter;
libzfs_fru_t **libzfs_fru_hash;

View File

@ -26,6 +26,7 @@
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
* Copyright 2017 Joyent, Inc.
* Copyright 2017 RackTop Systems.
* Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@ -34,25 +35,25 @@
* they are used by mount and unmount and when changing a filesystem's
* mountpoint.
*
* zfs_is_mounted()
* zfs_mount()
* zfs_unmount()
* zfs_unmountall()
* zfs_is_mounted()
* zfs_mount()
* zfs_unmount()
* zfs_unmountall()
*
* This file also contains the functions used to manage sharing filesystems via
* NFS and iSCSI:
*
* zfs_is_shared()
* zfs_share()
* zfs_unshare()
* zfs_is_shared()
* zfs_share()
* zfs_unshare()
*
* zfs_is_shared_nfs()
* zfs_is_shared_smb()
* zfs_share_proto()
* zfs_shareall();
* zfs_unshare_nfs()
* zfs_unshare_smb()
* zfs_unshareall_nfs()
* zfs_is_shared_nfs()
* zfs_is_shared_smb()
* zfs_share_proto()
* zfs_shareall();
* zfs_unshare_nfs()
* zfs_unshare_smb()
* zfs_unshareall_nfs()
* zfs_unshareall_smb()
* zfs_unshareall()
* zfs_unshareall_bypath()
@ -60,8 +61,8 @@
* The following functions are available for pool consumers, and will
* mount/unmount and share/unshare all datasets within pool:
*
* zpool_enable_datasets()
* zpool_disable_datasets()
* zpool_enable_datasets()
* zpool_disable_datasets()
*/
#include <dirent.h>
@ -83,10 +84,14 @@
#include <libzfs.h>
#include "libzfs_impl.h"
#include <thread_pool.h>
#include <libshare.h>
#define MAXISALEN 257 /* based on sysinfo(2) man page */
static int mount_tp_nthr = 512; /* tpool threads for multi-threaded mounting */
static void zfs_mount_task(void *);
static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
zfs_share_proto_t);
@ -1134,25 +1139,32 @@ remove_mountpoint(zfs_handle_t *zhp)
}
}
/*
* Add the given zfs handle to the cb_handles array, dynamically reallocating
* the array if it is out of space
*/
void
libzfs_add_handle(get_all_cb_t *cbp, zfs_handle_t *zhp)
{
if (cbp->cb_alloc == cbp->cb_used) {
size_t newsz;
void *ptr;
zfs_handle_t **newhandles;
newsz = cbp->cb_alloc ? cbp->cb_alloc * 2 : 64;
ptr = zfs_realloc(zhp->zfs_hdl,
cbp->cb_handles, cbp->cb_alloc * sizeof (void *),
newsz * sizeof (void *));
cbp->cb_handles = ptr;
newsz = cbp->cb_alloc != 0 ? cbp->cb_alloc * 2 : 64;
newhandles = zfs_realloc(zhp->zfs_hdl,
cbp->cb_handles, cbp->cb_alloc * sizeof (zfs_handle_t *),
newsz * sizeof (zfs_handle_t *));
cbp->cb_handles = newhandles;
cbp->cb_alloc = newsz;
}
cbp->cb_handles[cbp->cb_used++] = zhp;
}
/*
* Recursive helper function used during file system enumeration
*/
static int
mount_cb(zfs_handle_t *zhp, void *data)
zfs_iter_cb(zfs_handle_t *zhp, void *data)
{
get_all_cb_t *cbp = data;
@ -1178,104 +1190,362 @@ mount_cb(zfs_handle_t *zhp, void *data)
}
libzfs_add_handle(cbp, zhp);
if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
if (zfs_iter_filesystems(zhp, zfs_iter_cb, cbp) != 0) {
zfs_close(zhp);
return (-1);
}
return (0);
}
int
libzfs_dataset_cmp(const void *a, const void *b)
/*
* Sort comparator that compares two mountpoint paths. We sort these paths so
* that subdirectories immediately follow their parents. This means that we
* effectively treat the '/' character as the lowest value non-nul char.
* Since filesystems from non-global zones can have the same mountpoint
* as other filesystems, the comparator sorts global zone filesystems to
* the top of the list. This means that the global zone will traverse the
* filesystem list in the correct order and can stop when it sees the
* first zoned filesystem. In a non-global zone, only the delegated
* filesystems are seen.
*
* An example sorted list using this comparator would look like:
*
* /foo
* /foo/bar
* /foo/bar/baz
* /foo/baz
* /foo.bar
* /foo (NGZ1)
* /foo (NGZ2)
*
* The mount code depend on this ordering to deterministically iterate
* over filesystems in order to spawn parallel mount tasks.
*/
static int
mountpoint_cmp(const void *arga, const void *argb)
{
zfs_handle_t **za = (zfs_handle_t **)a;
zfs_handle_t **zb = (zfs_handle_t **)b;
zfs_handle_t *const *zap = arga;
zfs_handle_t *za = *zap;
zfs_handle_t *const *zbp = argb;
zfs_handle_t *zb = *zbp;
char mounta[MAXPATHLEN];
char mountb[MAXPATHLEN];
const char *a = mounta;
const char *b = mountb;
boolean_t gota, gotb;
uint64_t zoneda, zonedb;
if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0)
verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
zoneda = zfs_prop_get_int(za, ZFS_PROP_ZONED);
zonedb = zfs_prop_get_int(zb, ZFS_PROP_ZONED);
if (zoneda && !zonedb)
return (1);
if (!zoneda && zonedb)
return (-1);
gota = (zfs_get_type(za) == ZFS_TYPE_FILESYSTEM);
if (gota)
verify(zfs_prop_get(za, ZFS_PROP_MOUNTPOINT, mounta,
sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0)
verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
gotb = (zfs_get_type(zb) == ZFS_TYPE_FILESYSTEM);
if (gotb)
verify(zfs_prop_get(zb, ZFS_PROP_MOUNTPOINT, mountb,
sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
if (gota && gotb)
return (strcmp(mounta, mountb));
if (gota && gotb) {
while (*a != '\0' && (*a == *b)) {
a++;
b++;
}
if (*a == *b)
return (0);
if (*a == '\0')
return (-1);
if (*b == '\0')
return (1);
if (*a == '/')
return (-1);
if (*b == '/')
return (1);
return (*a < *b ? -1 : *a > *b);
}
if (gota)
return (-1);
if (gotb)
return (1);
return (strcmp(zfs_get_name(a), zfs_get_name(b)));
/*
* If neither filesystem has a mountpoint, revert to sorting by
* datset name.
*/
return (strcmp(zfs_get_name(za), zfs_get_name(zb)));
}
/*
* Reutrn true if path2 is a child of path1
*/
static boolean_t
libzfs_path_contains(const char *path1, const char *path2)
{
return (strstr(path2, path1) == path2 && path2[strlen(path1)] == '/');
}
static int
non_descendant_idx(zfs_handle_t **handles, size_t num_handles, int idx)
{
char parent[ZFS_MAXPROPLEN];
char child[ZFS_MAXPROPLEN];
int i;
verify(zfs_prop_get(handles[idx], ZFS_PROP_MOUNTPOINT, parent,
sizeof (parent), NULL, NULL, 0, B_FALSE) == 0);
for (i = idx + 1; i < num_handles; i++) {
verify(zfs_prop_get(handles[i], ZFS_PROP_MOUNTPOINT, child,
sizeof (child), NULL, NULL, 0, B_FALSE) == 0);
if (!libzfs_path_contains(parent, child))
break;
}
return (i);
}
typedef struct mnt_param {
libzfs_handle_t *mnt_hdl;
tpool_t *mnt_tp;
zfs_handle_t **mnt_zhps; /* filesystems to mount */
size_t mnt_num_handles;
int mnt_idx; /* Index of selected entry to mount */
zfs_iter_f mnt_func;
void *mnt_data;
} mnt_param_t;
/*
* Allocate and populate the parameter struct for mount function, and
* schedule mounting of the entry selected by idx.
*/
static void
zfs_dispatch_mount(libzfs_handle_t *hdl, zfs_handle_t **handles,
size_t num_handles, int idx, zfs_iter_f func, void *data, tpool_t *tp)
{
mnt_param_t *mnt_param = zfs_alloc(hdl, sizeof (mnt_param_t));
mnt_param->mnt_hdl = hdl;
mnt_param->mnt_tp = tp;
mnt_param->mnt_zhps = handles;
mnt_param->mnt_num_handles = num_handles;
mnt_param->mnt_idx = idx;
mnt_param->mnt_func = func;
mnt_param->mnt_data = data;
(void) tpool_dispatch(tp, zfs_mount_task, (void*)mnt_param);
}
/*
* This is the structure used to keep state of mounting or sharing operations
* during a call to zpool_enable_datasets().
*/
typedef struct mount_state {
/*
* ms_mntstatus is set to -1 if any mount fails. While multiple threads
* could update this variable concurrently, no synchronization is
* needed as it's only ever set to -1.
*/
int ms_mntstatus;
int ms_mntflags;
const char *ms_mntopts;
} mount_state_t;
static int
zfs_mount_one(zfs_handle_t *zhp, void *arg)
{
mount_state_t *ms = arg;
int ret = 0;
if (zfs_mount(zhp, ms->ms_mntopts, ms->ms_mntflags) != 0)
ret = ms->ms_mntstatus = -1;
return (ret);
}
static int
zfs_share_one(zfs_handle_t *zhp, void *arg)
{
mount_state_t *ms = arg;
int ret = 0;
if (zfs_share(zhp) != 0)
ret = ms->ms_mntstatus = -1;
return (ret);
}
/*
* Thread pool function to mount one file system. On completion, it finds and
* schedules its children to be mounted. This depends on the sorting done in
* zfs_foreach_mountpoint(). Note that the degenerate case (chain of entries
* each descending from the previous) will have no parallelism since we always
* have to wait for the parent to finish mounting before we can schedule
* its children.
*/
static void
zfs_mount_task(void *arg)
{
mnt_param_t *mp = arg;
int idx = mp->mnt_idx;
zfs_handle_t **handles = mp->mnt_zhps;
size_t num_handles = mp->mnt_num_handles;
char mountpoint[ZFS_MAXPROPLEN];
verify(zfs_prop_get(handles[idx], ZFS_PROP_MOUNTPOINT, mountpoint,
sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
if (mp->mnt_func(handles[idx], mp->mnt_data) != 0)
return;
/*
* We dispatch tasks to mount filesystems with mountpoints underneath
* this one. We do this by dispatching the next filesystem with a
* descendant mountpoint of the one we just mounted, then skip all of
* its descendants, dispatch the next descendant mountpoint, and so on.
* The non_descendant_idx() function skips over filesystems that are
* descendants of the filesystem we just dispatched.
*/
for (int i = idx + 1; i < num_handles;
i = non_descendant_idx(handles, num_handles, i)) {
char child[ZFS_MAXPROPLEN];
verify(zfs_prop_get(handles[i], ZFS_PROP_MOUNTPOINT,
child, sizeof (child), NULL, NULL, 0, B_FALSE) == 0);
if (!libzfs_path_contains(mountpoint, child))
break; /* not a descendant, return */
zfs_dispatch_mount(mp->mnt_hdl, handles, num_handles, i,
mp->mnt_func, mp->mnt_data, mp->mnt_tp);
}
free(mp);
}
/*
* Issue the func callback for each ZFS handle contained in the handles
* array. This function is used to mount all datasets, and so this function
* guarantees that filesystems for parent mountpoints are called before their
* children. As such, before issuing any callbacks, we first sort the array
* of handles by mountpoint.
*
* Callbacks are issued in one of two ways:
*
* 1. Sequentially: If the parallel argument is B_FALSE or the ZFS_SERIAL_MOUNT
* environment variable is set, then we issue callbacks sequentially.
*
* 2. In parallel: If the parallel argument is B_TRUE and the ZFS_SERIAL_MOUNT
* environment variable is not set, then we use a tpool to dispatch threads
* to mount filesystems in parallel. This function dispatches tasks to mount
* the filesystems at the top-level mountpoints, and these tasks in turn
* are responsible for recursively mounting filesystems in their children
* mountpoints.
*/
void
zfs_foreach_mountpoint(libzfs_handle_t *hdl, zfs_handle_t **handles,
size_t num_handles, zfs_iter_f func, void *data, boolean_t parallel)
{
zoneid_t zoneid = getzoneid();
/*
* The ZFS_SERIAL_MOUNT environment variable is an undocumented
* variable that can be used as a convenience to do a/b comparison
* of serial vs. parallel mounting.
*/
boolean_t serial_mount = !parallel ||
(getenv("ZFS_SERIAL_MOUNT") != NULL);
/*
* Sort the datasets by mountpoint. See mountpoint_cmp for details
* of how these are sorted.
*/
qsort(handles, num_handles, sizeof (zfs_handle_t *), mountpoint_cmp);
if (serial_mount) {
for (int i = 0; i < num_handles; i++) {
func(handles[i], data);
}
return;
}
/*
* Issue the callback function for each dataset using a parallel
* algorithm that uses a thread pool to manage threads.
*/
tpool_t *tp = tpool_create(1, mount_tp_nthr, 0, NULL);
/*
* There may be multiple "top level" mountpoints outside of the pool's
* root mountpoint, e.g.: /foo /bar. Dispatch a mount task for each of
* these.
*/
for (int i = 0; i < num_handles;
i = non_descendant_idx(handles, num_handles, i)) {
/*
* Since the mountpoints have been sorted so that the zoned
* filesystems are at the end, a zoned filesystem seen from
* the global zone means that we're done.
*/
if (zoneid == GLOBAL_ZONEID &&
zfs_prop_get_int(handles[i], ZFS_PROP_ZONED))
break;
zfs_dispatch_mount(hdl, handles, num_handles, i, func, data,
tp);
}
tpool_wait(tp); /* wait for all scheduled mounts to complete */
tpool_destroy(tp);
}
/*
* Mount and share all datasets within the given pool. This assumes that no
* datasets within the pool are currently mounted. Because users can create
* complicated nested hierarchies of mountpoints, we first gather all the
* datasets and mountpoints within the pool, and sort them by mountpoint. Once
* we have the list of all filesystems, we iterate over them in order and mount
* and/or share each one.
* datasets within the pool are currently mounted.
*/
#pragma weak zpool_mount_datasets = zpool_enable_datasets
int
zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
{
get_all_cb_t cb = { 0 };
libzfs_handle_t *hdl = zhp->zpool_hdl;
mount_state_t ms = { 0 };
zfs_handle_t *zfsp;
int i, ret = -1;
int *good;
int ret = 0;
/*
* Gather all non-snap datasets within the pool.
*/
if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL)
if ((zfsp = zfs_open(zhp->zpool_hdl, zhp->zpool_name,
ZFS_TYPE_DATASET)) == NULL)
goto out;
/*
* Gather all non-snapshot datasets within the pool. Start by adding
* the root filesystem for this pool to the list, and then iterate
* over all child filesystems.
*/
libzfs_add_handle(&cb, zfsp);
if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0)
goto out;
/*
* Sort the datasets by mountpoint.
*/
qsort(cb.cb_handles, cb.cb_used, sizeof (void *),
libzfs_dataset_cmp);
/*
* And mount all the datasets, keeping track of which ones
* succeeded or failed.
*/
if ((good = zfs_alloc(zhp->zpool_hdl,
cb.cb_used * sizeof (int))) == NULL)
if (zfs_iter_filesystems(zfsp, zfs_iter_cb, &cb) != 0)
goto out;
ret = 0;
for (i = 0; i < cb.cb_used; i++) {
if (zfs_mount(cb.cb_handles[i], mntopts, flags) != 0)
ret = -1;
else
good[i] = 1;
}
/*
* Mount all filesystems
*/
ms.ms_mntopts = mntopts;
ms.ms_mntflags = flags;
zfs_foreach_mountpoint(zhp->zpool_hdl, cb.cb_handles, cb.cb_used,
zfs_mount_one, &ms, B_TRUE);
if (ms.ms_mntstatus != 0)
ret = ms.ms_mntstatus;
/*
* Then share all the ones that need to be shared. This needs
* to be a separate pass in order to avoid excessive reloading
* of the configuration. Good should never be NULL since
* zfs_alloc is supposed to exit if memory isn't available.
* Share all filesystems that need to be shared. This needs to be
* a separate pass because libshare is not mt-safe, and so we need
* to share serially.
*/
for (i = 0; i < cb.cb_used; i++) {
if (good[i] && zfs_share(cb.cb_handles[i]) != 0)
ret = -1;
}
free(good);
ms.ms_mntstatus = 0;
zfs_foreach_mountpoint(zhp->zpool_hdl, cb.cb_handles, cb.cb_used,
zfs_share_one, &ms, B_FALSE);
if (ms.ms_mntstatus != 0)
ret = ms.ms_mntstatus;
out:
for (i = 0; i < cb.cb_used; i++)
for (int i = 0; i < cb.cb_used; i++)
zfs_close(cb.cb_handles[i]);
free(cb.cb_handles);

View File

@ -85,6 +85,8 @@ typedef struct progress_arg {
zfs_handle_t *pa_zhp;
int pa_fd;
boolean_t pa_parsable;
boolean_t pa_astitle;
uint64_t pa_size;
} progress_arg_t;
typedef struct dataref {
@ -930,6 +932,7 @@ typedef struct send_dump_data {
uint64_t prevsnap_obj;
boolean_t seenfrom, seento, replicate, doall, fromorigin;
boolean_t verbose, dryrun, parsable, progress, embed_data, std_out;
boolean_t progressastitle;
boolean_t large_block, compress;
int outfd;
boolean_t err;
@ -1110,14 +1113,14 @@ send_progress_thread(void *arg)
zfs_cmd_t zc = { 0 };
zfs_handle_t *zhp = pa->pa_zhp;
libzfs_handle_t *hdl = zhp->zfs_hdl;
unsigned long long bytes;
unsigned long long bytes, total;
char buf[16];
time_t t;
struct tm *tm;
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
if (!pa->pa_parsable)
if (!pa->pa_parsable && !pa->pa_astitle)
(void) fprintf(stderr, "TIME SENT SNAPSHOT\n");
/*
@ -1134,7 +1137,16 @@ send_progress_thread(void *arg)
tm = localtime(&t);
bytes = zc.zc_cookie;
if (pa->pa_parsable) {
if (pa->pa_astitle) {
int pct;
if (pa->pa_size > bytes)
pct = 100 * bytes / pa->pa_size;
else
pct = 100;
setproctitle("sending %s (%d%%: %llu/%llu)",
zhp->zfs_name, pct, bytes, pa->pa_size);
} else if (pa->pa_parsable) {
(void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n",
tm->tm_hour, tm->tm_min, tm->tm_sec,
bytes, zhp->zfs_name);
@ -1204,6 +1216,7 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
boolean_t isfromsnap, istosnap, fromorigin;
boolean_t exclude = B_FALSE;
FILE *fout = sdd->std_out ? stdout : stderr;
uint64_t size = 0;
err = 0;
thissnap = strchr(zhp->zfs_name, '@') + 1;
@ -1278,15 +1291,16 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
fromorigin = sdd->prevsnap[0] == '\0' &&
(sdd->fromorigin || sdd->replicate);
if (sdd->verbose) {
uint64_t size = 0;
if (sdd->progress && sdd->dryrun) {
(void) estimate_ioctl(zhp, sdd->prevsnap_obj,
fromorigin, flags, &size);
sdd->size += size;
}
if (sdd->verbose) {
send_print_verbose(fout, zhp->zfs_name,
sdd->prevsnap[0] ? sdd->prevsnap : NULL,
size, sdd->parsable);
sdd->size += size;
}
if (!sdd->dryrun) {
@ -1298,6 +1312,8 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
pa.pa_zhp = zhp;
pa.pa_fd = sdd->outfd;
pa.pa_parsable = sdd->parsable;
pa.pa_size = sdd->size;
pa.pa_astitle = sdd->progressastitle;
if ((err = pthread_create(&tid, NULL,
send_progress_thread, &pa)) != 0) {
@ -1580,6 +1596,7 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
int error = 0;
char name[ZFS_MAX_DATASET_NAME_LEN];
enum lzc_send_flags lzc_flags = 0;
uint64_t size = 0;
FILE *fout = (flags->verbose && flags->dryrun) ? stdout : stderr;
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
@ -1648,12 +1665,13 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
fromname = name;
}
if (flags->verbose) {
uint64_t size = 0;
if (flags->progress) {
error = lzc_send_space(zhp->zfs_name, fromname,
lzc_flags, &size);
if (error == 0)
size = MAX(0, (int64_t)(size - bytes));
}
if (flags->verbose) {
send_print_verbose(fout, zhp->zfs_name, fromname,
size, flags->parsable);
}
@ -1669,6 +1687,8 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
pa.pa_zhp = zhp;
pa.pa_fd = outfd;
pa.pa_parsable = flags->parsable;
pa.pa_size = size;
pa.pa_astitle = flags->progressastitle;
error = pthread_create(&tid, NULL,
send_progress_thread, &pa);
@ -1878,6 +1898,7 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
sdd.verbose = flags->verbose;
sdd.parsable = flags->parsable;
sdd.progress = flags->progress;
sdd.progressastitle = flags->progressastitle;
sdd.dryrun = flags->dryrun;
sdd.large_block = flags->largeblock;
sdd.embed_data = flags->embed_data;
@ -1914,7 +1935,7 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
sdd.cleanup_fd = -1;
sdd.snapholds = NULL;
}
if (flags->verbose || sdd.snapholds != NULL) {
if (flags->progress || sdd.snapholds != NULL) {
/*
* Do a verbose no-op dry run to get all the verbose output
* or to gather snapshot hold's before generating any data,

2427
contrib/bearssl/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
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.

45
contrib/bearssl/Makefile Normal file
View File

@ -0,0 +1,45 @@
# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
#
# 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.
# ======================================================================
# The lines below are a horrible hack that nonetheless works. On a
# "make" utility compatible with Single Unix v4 (this includes GNU and
# BSD make), the '\' at the end of a command line counts as an escape
# for the newline character, so the next line is still a comment.
# However, Microsoft's nmake.exe (that comes with Visual Studio) does
# not interpret the final '\' that way in a comment. The end result is
# that when using nmake.exe, this will include "mk/Win.mk", whereas
# GNU/BSD make will include "mk/Unix.mk".
# \
!ifndef 0 # \
!include mk/NMake.mk # \
!else
.POSIX:
include mk/SingleUnix.mk
# Extra hack for OpenBSD make.
ifndef: all
0: all
endif: all
# \
!endif

136
contrib/bearssl/README.txt Normal file
View File

@ -0,0 +1,136 @@
# Documentation
The most up-to-date documentation is supposed to be available on the
[BearSSL Web site](https://www.bearssl.org/).
# Disclaimer
BearSSL is considered beta-level software. Most planned functionalities
are implemented; new evolution may still break both source and binary
compatibility.
Using BearSSL for production purposes would be a relatively bold but not
utterly crazy move. BearSSL is free, open-source software, provided
without any guarantee of fitness or reliability. That being said, it
appears to behave properly, and only minor issues have been found (and
fixed) so far. You are encourage to inspect its API and code for
learning, testing and possibly contributing.
The usage license is explicited in the `LICENSE.txt` file. This is the
"MIT license". It can be summarised in the following way:
- You can use and reuse the library as you wish, and modify it, and
integrate it in your own code, and distribute it as is or in any
modified form, and so on.
- The only obligation that the license terms put upon you is that you
acknowledge and make it clear that if anything breaks, it is not my
fault, and I am not liable for anything, regardless of the type and
amount of collateral damage. The license terms say that the copyright
notice "shall be included in all copies or substantial portions of
the Software": this is how the disclaimer is "made explicit".
Basically, I have put it in every source file, so just keep it there.
# Installation
Right now, BearSSL is a simple library, along with a few test and debug
command-line tools. There is no installer yet. The library _can_ be
compiled as a shared library on some systems, but since the binary API
is not fully stabilised, this is not a very good idea to do that right
now.
To compile the code, just type `make`. This will try to use sane
"default" values. On a Windows system with Visual Studio, run a console
with the environment initialised for a specific version of the C compiler,
and type `nmake`.
To override the default settings, create a custom configuration file in
the `conf` directory, and invoke `make` (or `nmake`) with an explicit
`CONF=` parameter. For instance, to use the provided `samd20.mk`
configuration file (that targets cross-compilation for an Atmel board
that features a Cortex-M0+ CPU), type:
make CONF=samd20
The `conf/samd20.mk` file includes the `Unix.mk` file and then overrides
some of the parameters, including the destination directory. Any custom
configuration can be made the same way.
Some compile-time options can be set through macros, either on the
compiler command-line, or in the `src/config.h` file. See the comments
in that file. Some settings are autodetected but they can still be
explicitly overridden.
When compilation is done, the library (static and DLL, when appropriate)
and the command-line tools can be found in the designated build
directory (by default named `build`). The public headers (to be used
by applications linked against BearSSL) are in the `inc/` directory.
To run the tests:
- `testcrypto all` runs the cryptographic tests (test vectors on all
implemented cryptogaphic functions). It can be slow. You can also
run a selection of the tests by providing their names (run
`testcrypto` without any parameter to see the available names).
- `testspeed all` runs a number of performance benchmarks, there again
on cryptographic functions. It gives a taste of how things go on the
current platform. As for `testcrypto`, specific named benchmarks can
be executed.
- `testx509` runs X.509 validation tests. The test certificates are
all in `test/x509/`.
The `brssl` command-line tool produced in the build directory is a
stand-alone binary. It can exercise some of the functionalities of
BearSSL, in particular running a test SSL client or server. It is not
meant for production purposes (e.g. the SSL client has a mode where it
disregards the inability to validate the server's certificate, which is
inherently unsafe, but convenient for debug).
**Using the library** means writing some application code that invokes
it, and linking with the static library. The header files are all in the
`inc` directory; copy them wherever makes sense (e.g. in the
`/usr/local/include` directory). The library itself (`libbearssl.a`) is
what you link against.
Alternatively, you may want to copy the source files directly into your
own application code. This will make integrating ulterior versions of
BearSSL more difficult. If you still want to go down that road, then
simply copy all the `*.h` and `*.c` files from the `src` and `inc`
directories into your application source code. In the BearSSL source
archive, the source files are segregated into various sub-directories,
but this is for my convenience only. There is no technical requirement
for that, and all files can be dumped together in a simple directory.
Dependencies are simple and systematic:
- Each `*.c` file includes `inner.h`
- `inner.h` includes `config.h` and `bearssl.h`
- `bearssl.h` includes the other `bearssl_*.h`
# Versioning
I follow this simple version numbering scheme:
- Version numbers are `x.y` or `x.y.z` where `x`, `y` and `z` are
decimal integers (possibly greater than 10). When the `.z` part is
missing, it is equivalent to `.0`.
- Backward compatibility is maintained, at both source and binary levels,
for each major version: this means that if some application code was
designed for version `x.y`, then it should compile, link and run
properly with any version `x.y'` for any `y'` greater than `y`.
The major version `0` is an exception. You shall not expect that any
version that starts with `0.` offers any kind of compatibility,
either source or binary, with any other `0.` version. (Of course I
will try to maintain some decent level of source compatibility, but I
make no promise in that respect. Since the API uses caller-allocated
context structures, I already know that binary compatibility _will_
be broken.)
- Sub-versions (the `y` part) are about added functionality. That is,
it can be expected that `1.3` will contain some extra functions when
compared to `1.2`. The next version level (the `z` part) is for
bugfixes that do not add any functionality.

View File

@ -0,0 +1,112 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.IO;
using System.Text;
/*
* A simple class for writing out bytes as hexadecimal constants or
* explicit expressions for the initializer of a C array of 'unsigned
* char'. It starts every line with a given number of tabs, and aims at
* keeping lines below a given threshold (each indentation tab counts as
* 8 characters). An explicit newline is inserted before the first
* element, and commas are used as separators.
*/
class BlobWriter {
TextWriter w;
int maxLineLen;
int indent;
int lineLen;
/*
* Create a new instance. 'maxLineLen' is in characters, and
* 'indent' is the number of tab characters at the start of
* each line.
*/
internal BlobWriter(TextWriter w, int maxLineLen, int indent)
{
this.w = w;
this.maxLineLen = maxLineLen;
this.indent = indent;
lineLen = -1;
}
void DoNL()
{
w.WriteLine();
for (int i = 0; i < indent; i ++) {
w.Write('\t');
}
lineLen = (indent << 3);
}
/*
* Append a new byte value; it will be converted to an hexadecimal
* constant in the output.
*/
internal void Append(byte b)
{
if (lineLen < 0) {
DoNL();
} else {
w.Write(',');
lineLen ++;
if ((lineLen + 5) > maxLineLen) {
DoNL();
} else {
w.Write(' ');
lineLen ++;
}
}
w.Write("0x{0:X2}", b);
lineLen += 4;
}
/*
* Append a C expression, which will be used as is. The expression
* may resolve to several bytes if it uses internal commas. The
* writer will try to honour the expected line length, but it
* won't insert a newline character inside the expression.
*/
internal void Append(string expr)
{
if (lineLen < 0) {
DoNL();
} else {
w.Write(',');
lineLen ++;
if ((lineLen + 1 + expr.Length) > maxLineLen) {
DoNL();
} else {
w.Write(' ');
lineLen ++;
}
}
w.Write("{0}", expr);
lineLen += expr.Length;
}
}

181
contrib/bearssl/T0/CPU.cs Normal file
View File

@ -0,0 +1,181 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
/*
* Execution of code during compilation is done in a virtual CPU
* incarnated by this class, that contains the relevant registers.
*
* Accesses to the data on the stack are mapped to accesses to an
* internal array, with no explicit control on boundaries. Since the
* internal array may be larger than the actual stack contents,
* nonsensical accesses may still "work" to some extent. The whole
* thing won't derail beyond the CLR VM, though.
*/
class CPU {
/*
* Next instruction to execute is in ipBuf[ipOff].
*/
internal Opcode[] ipBuf;
internal int ipOff;
/*
* stackBuf and stackPtr implement the data stack. The system
* stack uses frames; 'rsp' points to the current top frame.
*/
TValue[] stackBuf;
int stackPtr;
Frame rsp;
internal CPU()
{
stackBuf = new TValue[16];
stackPtr = -1;
rsp = null;
}
/*
* Enter a function, reserving space for 'numLocals' local variables.
*/
internal void Enter(Opcode[] code, int numLocals)
{
Frame f = new Frame(rsp, numLocals);
rsp = f;
f.savedIpBuf = ipBuf;
f.savedIpOff = ipOff;
ipBuf = code;
ipOff = 0;
}
/*
* Exit the current function.
*/
internal void Exit()
{
ipBuf = rsp.savedIpBuf;
ipOff = rsp.savedIpOff;
rsp = rsp.upper;
}
/*
* Get the current stack depth (number of elements).
*/
internal int Depth {
get {
return stackPtr + 1;
}
}
/*
* Pop a value from the stack.
*/
internal TValue Pop()
{
return stackBuf[stackPtr --];
}
/*
* Push a value on the stack.
*/
internal void Push(TValue v)
{
int len = stackBuf.Length;
if (++ stackPtr == len) {
TValue[] nbuf = new TValue[len << 1];
Array.Copy(stackBuf, 0, nbuf, 0, len);
stackBuf = nbuf;
}
stackBuf[stackPtr] = v;
}
/*
* Look at the value at depth 'depth' (0 is top of stack). The
* stack is unchanged.
*/
internal TValue Peek(int depth)
{
return stackBuf[stackPtr - depth];
}
/*
* Rotate the stack at depth 'depth': the value at that depth
* is moved to the top of stack.
*/
internal void Rot(int depth)
{
TValue v = stackBuf[stackPtr - depth];
Array.Copy(stackBuf, stackPtr - (depth - 1),
stackBuf, stackPtr - depth, depth);
stackBuf[stackPtr] = v;
}
/*
* Inverse-rotate the stack at depth 'depth': the value at the
* top of stack is moved to that depth.
*/
internal void NRot(int depth)
{
TValue v = stackBuf[stackPtr];
Array.Copy(stackBuf, stackPtr - depth,
stackBuf, stackPtr - (depth - 1), depth);
stackBuf[stackPtr - depth] = v;
}
/*
* Get the current contents of the local variable 'num'.
*/
internal TValue GetLocal(int num)
{
return rsp.locals[num];
}
/*
* Set the contents of the local variable 'num'.
*/
internal void PutLocal(int num, TValue v)
{
rsp.locals[num] = v;
}
/*
* The system stack really is a linked list of Frame instances.
*/
class Frame {
internal Frame upper;
internal Opcode[] savedIpBuf;
internal int savedIpOff;
internal TValue[] locals;
internal Frame(Frame upper, int numLocals)
{
this.upper = upper;
locals = new TValue[numLocals];
}
}
}

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
abstract class CodeElement {
internal int Address { get; set; }
internal int LastLength { get; set; }
// internal abstract int Length { get; }
internal CodeElement()
{
Address = -1;
}
internal virtual void SetJumpTarget(CodeElement target)
{
throw new Exception("Code element accepts no target");
}
internal abstract int GetLength(bool oneByteCode);
internal abstract int Encode(BlobWriter bw, bool oneByteCode);
internal static int EncodeOneByte(uint val, BlobWriter bw)
{
if (val > 255) {
throw new Exception(string.Format(
"Cannot encode '{0}' over one byte", val));
}
bw.Append((byte)val);
return 1;
}
internal static int Encode7EUnsigned(uint val, BlobWriter bw)
{
int len = 1;
for (uint w = val; w >= 0x80; w >>= 7) {
len ++;
}
if (bw != null) {
for (int k = (len - 1) * 7; k >= 0; k -= 7) {
int x = (int)(val >> k) & 0x7F;
if (k > 0) {
x |= 0x80;
}
bw.Append((byte)x);
}
}
return len;
}
internal static int Encode7ESigned(int val, BlobWriter bw)
{
int len = 1;
if (val < 0) {
for (int w = val; w < -0x40; w >>= 7) {
len ++;
}
} else {
for (int w = val; w >= 0x40; w >>= 7) {
len ++;
}
}
if (bw != null) {
for (int k = (len - 1) * 7; k >= 0; k -= 7) {
int x = (int)(val >> k) & 0x7F;
if (k > 0) {
x |= 0x80;
}
bw.Append((byte)x);
}
}
return len;
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
class CodeElementJump : CodeElement {
uint jumpType;
CodeElement target;
internal CodeElementJump(uint jumpType)
{
this.jumpType = jumpType;
}
/* obsolete
internal override int Length {
get {
int len = Encode7EUnsigned(jumpType, null);
int joff = JumpOff;
if (joff == Int32.MinValue) {
len ++;
} else {
len += Encode7ESigned(joff, null);
}
return len;
}
}
*/
internal override int GetLength(bool oneByteCode)
{
int len = oneByteCode ? 1 : Encode7EUnsigned(jumpType, null);
int joff = JumpOff;
if (joff == Int32.MinValue) {
len ++;
} else {
len += Encode7ESigned(joff, null);
}
return len;
}
internal override void SetJumpTarget(CodeElement target)
{
this.target = target;
}
int JumpOff {
get {
if (target == null || Address < 0 || target.Address < 0)
{
return Int32.MinValue;
} else {
return target.Address - (Address + LastLength);
}
}
}
internal override int Encode(BlobWriter bw, bool oneByteCode)
{
if (bw == null) {
return GetLength(oneByteCode);
}
int len;
if (oneByteCode) {
len = EncodeOneByte(jumpType, bw);
} else {
len = Encode7EUnsigned(jumpType, bw);
}
int joff = JumpOff;
if (joff == Int32.MinValue) {
throw new Exception("Unresolved addresses");
}
return len + Encode7ESigned(joff, bw);
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
class CodeElementUInt : CodeElement {
uint val;
internal CodeElementUInt(uint val) : base()
{
this.val = val;
}
/* obsolete
internal override int Length {
get {
return Encode7EUnsigned(val, null);
}
}
*/
internal override int GetLength(bool oneByteCode)
{
return oneByteCode ? 1 : Encode7EUnsigned(val, null);
}
internal override int Encode(BlobWriter bw, bool oneByteCode)
{
return oneByteCode
? EncodeOneByte(val, bw)
: Encode7EUnsigned(val, bw);
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
class CodeElementUIntExpr : CodeElement {
uint val;
TPointerExpr cx;
int off;
internal CodeElementUIntExpr(uint val,
TPointerExpr cx, int off) : base()
{
this.val = val;
this.cx = cx;
this.off = off;
}
/* obsolete
internal override int Length {
get {
return Encode7EUnsigned(val, null)
+ (cx.GetMaxBitLength(off) + 6) / 7;
}
}
*/
internal override int GetLength(bool oneByteCode)
{
int len = oneByteCode ? 1 : Encode7EUnsigned(val, null);
return len + (cx.GetMaxBitLength(off) + 6) / 7;
}
internal override int Encode(BlobWriter bw, bool oneByteCode)
{
int len1 = oneByteCode
? EncodeOneByte(val, bw)
: Encode7EUnsigned(val, bw);
int len2 = (cx.GetMaxBitLength(off) + 6) / 7;
bw.Append(String.Format("T0_INT{0}({1})",
len2, cx.ToCExpr(off)));
return len1 + len2;
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
class CodeElementUIntInt : CodeElement {
uint val1;
int val2;
internal CodeElementUIntInt(uint val1, int val2) : base()
{
this.val1 = val1;
this.val2 = val2;
}
/* obsolete
internal override int Length {
get {
return Encode7EUnsigned(val1, null)
+ Encode7ESigned(val2, null);
}
}
*/
internal override int GetLength(bool oneByteCode)
{
return (oneByteCode ? 1 : Encode7EUnsigned(val1, null))
+ Encode7ESigned(val2, null);
}
internal override int Encode(BlobWriter bw, bool oneByteCode)
{
int len = oneByteCode
? EncodeOneByte(val1, bw)
: Encode7EUnsigned(val1, bw);
len += Encode7ESigned(val2, bw);
return len;
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
class CodeElementUIntUInt : CodeElement {
uint val1, val2;
internal CodeElementUIntUInt(uint val1, uint val2) : base()
{
this.val1 = val1;
this.val2 = val2;
}
/* obsolete
internal override int Length {
get {
return Encode7EUnsigned(val1, null)
+ Encode7EUnsigned(val2, null);
}
}
*/
internal override int GetLength(bool oneByteCode)
{
return (oneByteCode ? 1 : Encode7EUnsigned(val1, null))
+ Encode7EUnsigned(val2, null);
}
internal override int Encode(BlobWriter bw, bool oneByteCode)
{
int len = oneByteCode
? EncodeOneByte(val1, bw)
: Encode7EUnsigned(val1, bw);
len += Encode7EUnsigned(val2, bw);
return len;
}
}

View File

@ -0,0 +1,198 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
using System.Text;
class ConstData {
internal long ID { get; private set; }
internal int Address { get; set; }
internal int Length {
get {
return len;
}
}
byte[] buf;
int len;
internal ConstData(T0Comp ctx)
{
ID = ctx.NextBlobID();
buf = new byte[4];
len = 0;
}
void Expand(int elen)
{
int tlen = len + elen;
if (tlen > buf.Length) {
int nlen = Math.Max(buf.Length << 1, tlen);
byte[] nbuf = new byte[nlen];
Array.Copy(buf, 0, nbuf, 0, len);
buf = nbuf;
}
}
internal void Add8(byte b)
{
Expand(1);
buf[len ++] = b;
}
internal void Add16(int x)
{
Expand(2);
buf[len ++] = (byte)(x >> 8);
buf[len ++] = (byte)x;
}
internal void Add24(int x)
{
Expand(3);
buf[len ++] = (byte)(x >> 16);
buf[len ++] = (byte)(x >> 8);
buf[len ++] = (byte)x;
}
internal void Add32(int x)
{
Expand(4);
buf[len ++] = (byte)(x >> 24);
buf[len ++] = (byte)(x >> 16);
buf[len ++] = (byte)(x >> 8);
buf[len ++] = (byte)x;
}
internal void AddString(string s)
{
byte[] sd = Encoding.UTF8.GetBytes(s);
Expand(sd.Length + 1);
Array.Copy(sd, 0, buf, len, sd.Length);
buf[len + sd.Length] = 0;
len += sd.Length + 1;
}
void CheckIndex(int off, int dlen)
{
if (off < 0 || off > (len - dlen)) {
throw new IndexOutOfRangeException();
}
}
internal void Set8(int off, byte v)
{
CheckIndex(off, 1);
buf[off] = v;
}
internal byte Read8(int off)
{
CheckIndex(off, 1);
return buf[off];
}
internal int Read16(int off)
{
CheckIndex(off, 2);
return (buf[off] << 8) | buf[off + 1];
}
internal int Read24(int off)
{
CheckIndex(off, 3);
return (buf[off] << 16) | (buf[off + 1] << 8) | buf[off + 2];
}
internal int Read32(int off)
{
CheckIndex(off, 4);
return (buf[off] << 24) | (buf[off + 1] << 16)
| (buf[off + 2] << 8) | buf[off + 3];
}
internal string ToString(int off)
{
StringBuilder sb = new StringBuilder();
for (;;) {
int x = DecodeUTF8(ref off);
if (x == 0) {
return sb.ToString();
}
if (x < 0x10000) {
sb.Append((char)x);
} else {
x -= 0x10000;
sb.Append((char)(0xD800 + (x >> 10)));
sb.Append((char)(0xDC00 + (x & 0x3FF)));
}
}
}
int DecodeUTF8(ref int off)
{
if (off >= len) {
throw new IndexOutOfRangeException();
}
int x = buf[off ++];
if (x < 0xC0 || x > 0xF7) {
return x;
}
int elen, acc;
if (x >= 0xF0) {
elen = 3;
acc = x & 0x07;
} else if (x >= 0xE0) {
elen = 2;
acc = x & 0x0F;
} else {
elen = 1;
acc = x & 0x1F;
}
if (off + elen > len) {
return x;
}
for (int i = 0; i < elen; i ++) {
int y = buf[off + i];
if (y < 0x80 || y >= 0xC0) {
return x;
}
acc = (acc << 6) + (y & 0x3F);
}
if (acc > 0x10FFFF) {
return x;
}
off += elen;
return acc;
}
internal void Encode(BlobWriter bw)
{
for (int i = 0; i < len; i ++) {
bw.Append(buf[i]);
}
}
}

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
abstract class Opcode {
internal Opcode()
{
}
/*
* Execute this opcode.
*/
internal abstract void Run(CPU cpu);
/*
* Resolve the target (word reference) for this opcode.
*/
internal virtual void ResolveTarget(Word target)
{
throw new Exception("Not a call opcode");
}
/*
* Resolve the jump offset for this opcode. Displacement is
* relative to the address of the opcode that immediately follows
* the jump code; thus, 0 implies no jump at all.
*/
internal virtual void ResolveJump(int disp)
{
throw new Exception("Not a jump opcode");
}
/*
* Get the Word that this opcode references; this can happen
* only with "call" and "const" opcodes. For all other opcodes,
* this method returns null.
*/
internal virtual Word GetReference(T0Comp ctx)
{
return null;
}
/*
* Get the data block that this opcode references; this can happen
* only with "const" opcodes. For all other opcodes, this method
* returns null.
*/
internal virtual ConstData GetDataBlock(T0Comp ctx)
{
return null;
}
/*
* Test whether this opcode may "fall through", i.e. execution
* may at least potentially proceed to the next opcode.
*/
internal virtual bool MayFallThrough {
get {
return true;
}
}
/*
* Get jump displacement. For non-jump opcodes, this returns 0.
*/
internal virtual int JumpDisp {
get {
return 0;
}
}
/*
* Get stack effect for this opcode (number of elements added to
* the stack, could be negative). For OpcodeCall, this returns
* 0.
*/
internal virtual int StackAction {
get {
return 0;
}
}
internal abstract CodeElement ToCodeElement();
/*
* This method is called for the CodeElement corresponding to
* this opcode, at gcode[off]; it is used to compute actual
* byte jump offsets when converting code to C.
*/
internal virtual void FixUp(CodeElement[] gcode, int off)
{
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class OpcodeCall : Opcode {
Word target;
internal OpcodeCall() : this(null)
{
}
internal OpcodeCall(Word target)
{
this.target = target;
}
internal override void ResolveTarget(Word target)
{
if (this.target != null) {
throw new Exception("Opcode already resolved");
}
this.target = target;
}
internal override void Run(CPU cpu)
{
target.Run(cpu);
}
internal override Word GetReference(T0Comp ctx)
{
if (target == null) {
throw new Exception("Unresolved call target");
}
return target;
}
internal override CodeElement ToCodeElement()
{
return new CodeElementUInt((uint)target.Slot);
}
public override string ToString()
{
return "call " + (target == null ? "UNRESOLVED" : target.Name);
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class OpcodeConst : Opcode {
TValue val;
internal OpcodeConst(TValue val)
{
this.val = val;
}
internal override void Run(CPU cpu)
{
cpu.Push(val);
}
internal override Word GetReference(T0Comp ctx)
{
TPointerXT xt = val.ptr as TPointerXT;
if (xt == null) {
return null;
}
xt.Resolve(ctx);
return xt.Target;
}
internal override ConstData GetDataBlock(T0Comp ctx)
{
TPointerBlob bp = val.ptr as TPointerBlob;
return bp == null ? null : bp.Blob;
}
internal override CodeElement ToCodeElement()
{
if (val.ptr == null) {
return new CodeElementUIntInt(1, val.Int);
}
TPointerXT xt = val.ptr as TPointerXT;
if (xt != null) {
if (val.x != 0) {
throw new Exception(
"Cannot compile XT: non-zero offset");
}
return new CodeElementUIntInt(1, xt.Target.Slot);
}
TPointerBlob bp = val.ptr as TPointerBlob;
if (bp != null) {
return new CodeElementUIntInt(1,
val.x + bp.Blob.Address);
}
TPointerExpr cx = val.ptr as TPointerExpr;
if (cx != null) {
return new CodeElementUIntExpr(1, cx, val.x);
}
throw new Exception(String.Format(
"Cannot embed constant (type = {0})",
val.ptr.GetType().FullName));
}
internal override int StackAction {
get {
return 1;
}
}
public override string ToString()
{
return "const " + val.ToString();
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class OpcodeGetLocal : Opcode {
int num;
internal OpcodeGetLocal(int num)
{
this.num = num;
}
internal override void Run(CPU cpu)
{
cpu.Push(cpu.GetLocal(num));
}
internal override CodeElement ToCodeElement()
{
return new CodeElementUIntUInt(2, (uint)num);
}
internal override int StackAction {
get {
return 1;
}
}
public override string ToString()
{
return "getlocal " + num;
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
abstract class OpcodeJump : Opcode {
int disp;
internal OpcodeJump() : this(Int32.MinValue)
{
}
internal OpcodeJump(int disp)
{
this.disp = disp;
}
internal override int JumpDisp {
get {
return disp;
}
}
internal override void Run(CPU cpu)
{
cpu.ipOff += disp;
}
internal override void ResolveJump(int disp)
{
if (this.disp != Int32.MinValue) {
throw new Exception("Jump already resolved");
}
this.disp = disp;
}
internal override void FixUp(CodeElement[] gcode, int off)
{
gcode[off].SetJumpTarget(gcode[off + 1 + disp]);
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class OpcodeJumpIf : OpcodeJump {
internal OpcodeJumpIf() : base()
{
}
internal OpcodeJumpIf(int disp) : base(disp)
{
}
internal override void Run(CPU cpu)
{
TValue v = cpu.Pop();
if (v.Bool) {
base.Run(cpu);
}
}
internal override int StackAction {
get {
return -1;
}
}
internal override CodeElement ToCodeElement()
{
return new CodeElementJump(5);
}
public override string ToString()
{
if (JumpDisp == Int32.MinValue) {
return "jumpif UNRESOLVED";
} else {
return "jumpif disp=" + JumpDisp;
}
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class OpcodeJumpIfNot : OpcodeJump {
internal OpcodeJumpIfNot() : base()
{
}
internal OpcodeJumpIfNot(int disp) : base(disp)
{
}
internal override void Run(CPU cpu)
{
TValue v = cpu.Pop();
if (!v.Bool) {
base.Run(cpu);
}
}
internal override int StackAction {
get {
return -1;
}
}
internal override CodeElement ToCodeElement()
{
return new CodeElementJump(6);
}
public override string ToString()
{
if (JumpDisp == Int32.MinValue) {
return "jumpifnot UNRESOLVED";
} else {
return "jumpifnot disp=" + JumpDisp;
}
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class OpcodeJumpUncond : OpcodeJump {
internal OpcodeJumpUncond() : base()
{
}
internal OpcodeJumpUncond(int disp) : base(disp)
{
}
/*
* Unconditional jumps do not "fall through" unless they
* happen to be a jump to the next instruction...
*/
internal override bool MayFallThrough {
get {
return JumpDisp == 0;
}
}
internal override CodeElement ToCodeElement()
{
return new CodeElementJump(4);
}
public override string ToString()
{
if (JumpDisp == Int32.MinValue) {
return "jump UNRESOLVED";
} else {
return "jump disp=" + JumpDisp;
}
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class OpcodePutLocal : Opcode {
int num;
internal OpcodePutLocal(int num)
{
this.num = num;
}
internal override void Run(CPU cpu)
{
cpu.PutLocal(num, cpu.Pop());
}
internal override CodeElement ToCodeElement()
{
return new CodeElementUIntUInt(3, (uint)num);
}
internal override int StackAction {
get {
return -1;
}
}
public override string ToString()
{
return "putlocal " + num;
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class OpcodeRet : Opcode {
internal override void Run(CPU cpu)
{
cpu.Exit();
}
internal override bool MayFallThrough {
get {
return false;
}
}
internal override CodeElement ToCodeElement()
{
return new CodeElementUInt(0);
}
public override string ToString()
{
return "ret";
}
}

129
contrib/bearssl/T0/SType.cs Normal file
View File

@ -0,0 +1,129 @@
using System;
/*
* This structure contains the stack effect of a word: number of stack
* element consumed on input, and number of stack element produced on
* output.
*/
struct SType {
/*
* Get number of stack elements consumed on input; this is -1 if
* the stack effect is not known.
*/
internal int DataIn {
get {
return din;
}
}
/*
* Get number of stack elements produced on output; this is -1 if
* either the stack effect is not known, or if the word never
* exits.
*/
internal int DataOut {
get {
return dout;
}
}
/*
* Tell whether the stack effect is known.
*/
internal bool IsKnown {
get {
return din >= 0;
}
}
/*
* Tell whether the stack effect is known and the word never exits.
*/
internal bool NoExit {
get {
return din >= 0 && dout < 0;
}
}
int din, dout;
internal SType(int din, int dout)
{
if (din < 0) {
din = -1;
}
if (dout < 0) {
dout = -1;
}
this.din = din;
this.dout = dout;
}
/*
* Special value for the unknown stack effect.
*/
internal static SType UNKNOWN = new SType(-1, -1);
/*
* Constant for the "blank stack effect".
*/
internal static SType BLANK = new SType(0, 0);
public static bool operator ==(SType s1, SType s2)
{
return s1.din == s2.din && s1.dout == s2.dout;
}
public static bool operator !=(SType s1, SType s2)
{
return s1.din != s2.din || s1.dout != s2.dout;
}
public override bool Equals(Object obj)
{
return (obj is SType) && ((SType)obj == this);
}
public override int GetHashCode()
{
return din * 31 + dout * 17;
}
public override string ToString()
{
if (!IsKnown) {
return "UNKNOWN";
} else if (NoExit) {
return string.Format("in:{0},noexit", din);
} else {
return string.Format("in:{0},out:{1}", din, dout);
}
}
/*
* Test whether this stack effect is a sub-effect of the provided
* stack effect s. Stack effect s1 is a sub-effect of stack-effect
* s2 if any of the following holds:
* -- s1 and s2 are known, s1.din <= s2.din and s1 does not exit.
* -- s1 and s2 are known, s1.din <= s2.din, s1 and s2 exit,
* and s1.din - s1.dout == s2.din - s2.dout.
*/
internal bool IsSubOf(SType s)
{
if (!IsKnown || !s.IsKnown) {
return false;
}
if (din > s.din) {
return false;
}
if (NoExit) {
return true;
}
if (s.NoExit) {
return false;
}
return (din - dout) == (s.din - s.dout);
}
}

2123
contrib/bearssl/T0/T0Comp.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class TPointerBase {
/* obsolete
internal virtual TValue Get(TValue vp)
{
throw new Exception(
"cannot get values from this pointer");
}
internal virtual void Set(TValue vp, TValue nval)
{
throw new Exception(
"cannot set values to this pointer");
}
*/
internal virtual bool ToBool(TValue vp)
{
return true;
}
internal virtual void Execute(T0Comp ctx, CPU cpu)
{
throw new Exception("value is not an xt: " + ToString());
}
internal virtual string ToString(TValue vp)
{
return String.Format("{0}+{1}",
GetType().Name, vp.x);
}
internal virtual bool Equals(TPointerBase tp)
{
return this == tp;
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class TPointerBlob : TPointerBase {
internal ConstData Blob { get; private set; }
internal TPointerBlob(ConstData cd)
{
this.Blob = cd;
}
internal TPointerBlob(T0Comp owner, string s)
{
Blob = new ConstData(owner);
Blob.AddString(s);
}
/* obsolete
internal override TValue Get8(TValue vp)
{
return new TValue((int)Blob.Read8(vp.x));
}
internal override TValue Get16(TValue vp)
{
return new TValue((int)Blob.Read16(vp.x));
}
internal override TValue Get24(TValue vp)
{
return new TValue((int)Blob.Read24(vp.x));
}
internal override TValue Get32(TValue vp)
{
return new TValue((int)Blob.Read32(vp.x));
}
*/
internal override string ToString(TValue vp)
{
return Blob.ToString(vp.x);
}
internal override bool Equals(TPointerBase tp)
{
TPointerBlob tb = tp as TPointerBlob;
return tb != null && Blob == tb.Blob;
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
class TPointerExpr : TPointerBase {
string expr;
int min, max;
internal TPointerExpr(string expr, int min, int max)
{
this.expr = expr;
this.min = min;
this.max = max;
}
internal override bool ToBool(TValue vp)
{
throw new Exception("Cannot evaluate C-expr at compile time");
}
internal override string ToString(TValue vp)
{
return ToCExpr(vp.x);
}
internal string ToCExpr(int off)
{
if (off == 0) {
return expr;
} else if (off > 0) {
return String.Format(
"(uint32_t)({0}) + {1}", expr, off);
} else {
return String.Format(
"(uint32_t)({0}) - {1}", expr, -(long)off);
}
}
internal int GetMaxBitLength(int off)
{
long rmin = (long)min + off;
long rmax = (long)max + off;
int numBits = 1;
if (rmin < 0) {
numBits = Math.Max(numBits, BitLength(rmin));
}
if (rmax > 0) {
numBits = Math.Max(numBits, BitLength(rmax));
}
return Math.Min(numBits, 32);
}
/*
* Get the minimal bit length of a value. This is for a signed
* representation: the length includes a sign bit. Thus, the
* returned value will be at least 1.
*/
static int BitLength(long v)
{
int num = 1;
if (v < 0) {
while (v != -1) {
num ++;
v >>= 1;
}
} else {
while (v != 0) {
num ++;
v >>= 1;
}
}
return num;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class TPointerNull : TPointerBase {
internal override bool ToBool(TValue vp)
{
return false;
}
internal override string ToString(TValue vp)
{
return "null";
}
internal override bool Equals(TPointerBase tp)
{
return tp is TPointerNull;
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class TPointerXT : TPointerBase {
internal string Name {
get; private set;
}
internal Word Target {
get; private set;
}
internal TPointerXT(string name)
{
this.Name = name;
this.Target = null;
}
internal TPointerXT(Word target)
{
this.Name = target.Name;
this.Target = target;
}
internal void Resolve(T0Comp ctx)
{
if (Target == null) {
Target = ctx.Lookup(Name);
}
}
internal override void Execute(T0Comp ctx, CPU cpu)
{
Resolve(ctx);
Target.Run(cpu);
}
internal override string ToString(TValue vp)
{
return String.Format("<'{0}>", Name);
}
internal override bool Equals(TPointerBase tp)
{
TPointerXT tx = tp as TPointerXT;
return tx != null && Name == tx.Name;
}
}

View File

@ -0,0 +1,231 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
/*
* Each value is represented with a TValue structure. Integers use the 'x'
* field, and 'ptr' is null; for pointers, the 'ptr' field is used, and the
* 'x' is then an offset in the object represented by 'ptr'.
*/
struct TValue {
internal int x;
internal TPointerBase ptr;
internal TValue(int x)
{
this.x = x;
this.ptr = null;
}
internal TValue(uint x)
{
this.x = (int)x;
this.ptr = null;
}
internal TValue(bool b)
{
this.x = b ? -1 : 0;
this.ptr = null;
}
internal TValue(int x, TPointerBase ptr)
{
this.x = x;
this.ptr = ptr;
}
/*
* Convert this value to a boolean; integer 0 and null pointer are
* 'false', other values are 'true'.
*/
internal bool Bool {
get {
if (ptr == null) {
return x != 0;
} else {
return ptr.ToBool(this);
}
}
}
/*
* Get this value as an integer. Pointers cannot be converted to
* integers.
*/
internal int Int {
get {
if (ptr == null) {
return x;
}
throw new Exception("not an integer: " + ToString());
}
}
/*
* Get this value as an unsigned integer. This is the integer
* value, reduced modulo 2^32 in the 0..2^32-1 range.
*/
internal uint UInt {
get {
return (uint)Int;
}
}
/*
* String format of integers uses decimal representation. For
* pointers, this depends on the pointed-to value.
*/
public override string ToString()
{
if (ptr == null) {
return String.Format("{0}", x);
} else {
return ptr.ToString(this);
}
}
/*
* If this value is an XT, then execute it. Otherwise, an exception
* is thrown.
*/
internal void Execute(T0Comp ctx, CPU cpu)
{
ToXT().Execute(ctx, cpu);
}
/*
* Convert this value to an XT. On failure, an exception is thrown.
*/
internal TPointerXT ToXT()
{
TPointerXT xt = ptr as TPointerXT;
if (xt == null) {
throw new Exception(
"value is not an xt: " + ToString());
}
return xt;
}
/*
* Compare this value to another.
*/
internal bool Equals(TValue v)
{
if (x != v.x) {
return false;
}
if (ptr == v.ptr) {
return true;
}
if (ptr == null || v.ptr == null) {
return false;
}
return ptr.Equals(v.ptr);
}
public static implicit operator TValue(bool val)
{
return new TValue(val);
}
public static implicit operator TValue(sbyte val)
{
return new TValue((int)val);
}
public static implicit operator TValue(byte val)
{
return new TValue((int)val);
}
public static implicit operator TValue(short val)
{
return new TValue((int)val);
}
public static implicit operator TValue(ushort val)
{
return new TValue((int)val);
}
public static implicit operator TValue(char val)
{
return new TValue((int)val);
}
public static implicit operator TValue(int val)
{
return new TValue((int)val);
}
public static implicit operator TValue(uint val)
{
return new TValue((int)val);
}
public static implicit operator bool(TValue v)
{
return v.Bool;
}
public static implicit operator sbyte(TValue v)
{
return (sbyte)v.Int;
}
public static implicit operator byte(TValue v)
{
return (byte)v.Int;
}
public static implicit operator short(TValue v)
{
return (short)v.Int;
}
public static implicit operator ushort(TValue v)
{
return (ushort)v.Int;
}
public static implicit operator char(TValue v)
{
return (char)v.Int;
}
public static implicit operator int(TValue v)
{
return (int)v.Int;
}
public static implicit operator uint(TValue v)
{
return (uint)v.Int;
}
}

172
contrib/bearssl/T0/Word.cs Normal file
View File

@ -0,0 +1,172 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
/*
* A "word" is a function with a name. Words can be either native or
* interpreted; native words are implemented as some in-compiler special
* code.
*
* Some native words (not all of them) have a C implementation and can
* thus be part of the generated C code. Native words with no C
* implementation can be used only during compilation; this is typically
* the case for words that support the syntax (e.g. 'if').
*/
abstract class Word {
/*
* The compiler context for this word.
*/
internal T0Comp TC {
get; private set;
}
/*
* Immediate words are executed immediately when encountered in the
* source code, even while compiling another word.
*/
internal bool Immediate {
get; set;
}
/*
* Each word has a unique name. Names are case-sensitive.
*/
internal string Name {
get; private set;
}
/*
* Words are allocated slot numbers when output code is generated.
*/
internal int Slot {
get; set;
}
/*
* Each word may have a known stack effect.
*/
internal SType StackEffect {
get; set;
}
internal Word(T0Comp owner, string name)
{
TC = owner;
Name = name;
StackEffect = SType.UNKNOWN;
}
/*
* Resolving a word means looking up all references to external
* words.
*/
internal virtual void Resolve()
{
}
/*
* Execute this word. If the word is native, then its code is
* run right away; if the word is interpreted, then the entry
* sequence is executed.
*/
internal virtual void Run(CPU cpu)
{
throw new Exception(String.Format(
"cannot run '{0}' at compile-time", Name));
}
/*
* All words may have an explicit C implementations. To be part
* of the generated C code, a word must either be interpreted,
* or have an explicit C implementation, or both.
*/
internal string CCode {
get; set;
}
/*
* Get all words referenced from this one. This implies
* resolving the word.
*/
internal virtual List<Word> GetReferences()
{
return new List<Word>();
}
/*
* Get all data blocks directly referenced from this one. This
* implies resolving the word.
*/
internal virtual List<ConstData> GetDataBlocks()
{
return new List<ConstData>();
}
/*
* Produce the code elements for this word.
*/
internal virtual void GenerateCodeElements(List<CodeElement> dst)
{
throw new Exception("Word does not yield code elements");
}
/*
* Compute/verify stack effect for this word.
*/
internal virtual void AnalyseFlow()
{
}
/*
* Get maximum data stack usage for this word. This is the number
* of extra slots that this word may need on the data stack. If
* the stack effect is not known, this returns -1.
*/
internal virtual int MaxDataStack {
get {
SType se = StackEffect;
if (!se.IsKnown) {
return -1;
}
if (se.NoExit) {
return 0;
} else {
return Math.Min(0, se.DataOut - se.DataIn);
}
}
}
/*
* Get maximum return stack usage for this word.
*/
internal virtual int MaxReturnStack {
get {
return 0;
}
}
}

View File

@ -0,0 +1,385 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
/*
* A WordBuilder instance organizes construction of a new interpreted word.
*
* Opcodes are accumulated with specific methods. A control-flow stack
* is maintained to resolve jumps.
*
* Each instance shall be used for only one word.
*/
class WordBuilder {
T0Comp TC;
string name;
int[] cfStack;
int cfPtr;
List<Opcode> code;
List<string> toResolve;
Dictionary<string, int> locals;
bool jumpToLast;
internal SType StackEffect {
get; set;
}
/*
* Create a new instance, with the specified word name.
*/
internal WordBuilder(T0Comp TC, string name)
{
this.TC = TC;
this.name = name;
cfStack = new int[16];
cfPtr = -1;
code = new List<Opcode>();
toResolve = new List<string>();
locals = new Dictionary<string, int>();
jumpToLast = true;
StackEffect = SType.UNKNOWN;
}
/*
* Build the word. The control-flow stack must be empty. A 'ret'
* opcode is automatically appended if required.
*/
internal Word Build()
{
if (cfPtr != -1) {
throw new Exception("control-flow stack is not empty");
}
if (jumpToLast || code[code.Count - 1].MayFallThrough) {
Ret();
}
Word w = new WordInterpreted(TC, name, locals.Count,
code.ToArray(), toResolve.ToArray());
w.StackEffect = StackEffect;
return w;
}
void Add(Opcode op)
{
Add(op, null);
}
void Add(Opcode op, string refName)
{
code.Add(op);
toResolve.Add(refName);
jumpToLast = false;
}
/*
* Rotate the control-flow stack at depth 'depth'.
*/
internal void CSRoll(int depth)
{
int x = cfStack[cfPtr - depth];
Array.Copy(cfStack, cfPtr - (depth - 1),
cfStack, cfPtr - depth, depth);
cfStack[cfPtr] = x;
}
/*
* Make a copy of the control-flow element at depth 'depth', and
* push it on top of the control-flow stack.
*/
internal void CSPick(int depth)
{
int x = cfStack[cfPtr - depth];
CSPush(x);
}
void CSPush(int x)
{
int len = cfStack.Length;
if (++ cfPtr == len) {
int[] ncf = new int[len << 1];
Array.Copy(cfStack, 0, ncf, 0, len);
cfStack = ncf;
}
cfStack[cfPtr] = x;
}
int CSPop()
{
return cfStack[cfPtr --];
}
/*
* Push an origin on the control-flow stack, corresponding to the
* next opcode to add.
*/
internal void CSPushOrig()
{
CSPush(code.Count);
}
/*
* Push a destination on the control-flow stack, corresponding to
* the next opcode to add.
*/
internal void CSPushDest()
{
CSPush(-code.Count - 1);
}
/*
* Pop an origin from the control-flow stack. An exception is
* thrown if the value is not an origin.
*/
internal int CSPopOrig()
{
int x = CSPop();
if (x < 0) {
throw new Exception("not an origin");
}
return x;
}
/*
* Pop a destination from the control-flow stack. An exception is
* thrown if the value is not a destination.
*/
internal int CSPopDest()
{
int x = CSPop();
if (x >= 0) {
throw new Exception("not a destination");
}
return -x - 1;
}
/*
* Add a "push literal" opcode.
*/
internal void Literal(TValue v)
{
Add(new OpcodeConst(v));
}
/*
* Compile a "call" by name. This method implements the support
* for local variables:
*
* - If the target is '>' followed by a local variable name, then
* a "put local" opcode is added.
*
* - Otherwise, if the target is a local variable name, then a
* "get local" opcode is added.
*
* - Otherwise, a call to the named word is added. The target name
* will be resolved later on (typically, when the word containing
* the call opcode is first invoked, or when C code is generated).
*/
internal void Call(string target)
{
string lname;
bool write;
if (target.StartsWith(">")) {
lname = target.Substring(1);
write = true;
} else {
lname = target;
write = false;
}
int lnum;
if (locals.TryGetValue(lname, out lnum)) {
if (write) {
Add(new OpcodePutLocal(lnum));
} else {
Add(new OpcodeGetLocal(lnum));
}
} else {
Add(new OpcodeCall(), target);
}
}
/*
* Add a "call" opcode to the designated word.
*/
internal void CallExt(Word wtarget)
{
Add(new OpcodeCall(wtarget), null);
}
/*
* Add a "call" opcode to a word which is not currently resolved.
* This method ignores local variables.
*/
internal void CallExt(string target)
{
Add(new OpcodeCall(), target);
}
/*
* Add a "get local" opcode; the provided local name must already
* be defined.
*/
internal void GetLocal(string name)
{
int lnum;
if (locals.TryGetValue(name, out lnum)) {
Add(new OpcodeGetLocal(lnum));
} else {
throw new Exception("no such local: " + name);
}
}
/*
* Add a "put local" opcode; the provided local name must already
* be defined.
*/
internal void PutLocal(string name)
{
int lnum;
if (locals.TryGetValue(name, out lnum)) {
Add(new OpcodePutLocal(lnum));
} else {
throw new Exception("no such local: " + name);
}
}
/*
* Define a new local name.
*/
internal void DefLocal(string lname)
{
if (locals.ContainsKey(lname)) {
throw new Exception(String.Format(
"local already defined: {0}", lname));
}
locals[lname] = locals.Count;
}
/*
* Add a "call" opcode whose target is an XT value (which may be
* resolved or as yet unresolved).
*/
internal void Call(TPointerXT xt)
{
if (xt.Target == null) {
Add(new OpcodeCall(), xt.Name);
} else {
Add(new OpcodeCall(xt.Target));
}
}
/*
* Add a "ret" opcode.
*/
internal void Ret()
{
Add(new OpcodeRet());
}
/*
* Add a forward unconditional jump. The new opcode address is
* pushed on the control-flow stack as an origin.
*/
internal void Ahead()
{
CSPushOrig();
Add(new OpcodeJumpUncond());
}
/*
* Add a forward conditional jump, which will be taken at runtime
* if the top-of-stack value is 'true'. The new opcode address is
* pushed on the control-flow stack as an origin.
*/
internal void AheadIf()
{
CSPushOrig();
Add(new OpcodeJumpIf());
}
/*
* Add a forward conditional jump, which will be taken at runtime
* if the top-of-stack value is 'false'. The new opcode address is
* pushed on the control-flow stack as an origin.
*/
internal void AheadIfNot()
{
CSPushOrig();
Add(new OpcodeJumpIfNot());
}
/*
* Resolve a previous forward jump to the current code address.
* The top of control-flow stack is popped and must be an origin.
*/
internal void Then()
{
int x = CSPopOrig();
code[x].ResolveJump(code.Count - x - 1);
jumpToLast = true;
}
/*
* Push the current code address on the control-flow stack as a
* destination, to be used by an ulterior backward jump.
*/
internal void Begin()
{
CSPushDest();
}
/*
* Add a backward unconditional jump. The jump target is popped
* from the control-flow stack as a destination.
*/
internal void Again()
{
int x = CSPopDest();
Add(new OpcodeJumpUncond(x - code.Count - 1));
}
/*
* Add a backward conditional jump, which will be taken at runtime
* if the top-of-stack value is 'true'. The jump target is popped
* from the control-flow stack as a destination.
*/
internal void AgainIf()
{
int x = CSPopDest();
Add(new OpcodeJumpIf(x - code.Count - 1));
}
/*
* Add a backward conditional jump, which will be taken at runtime
* if the top-of-stack value is 'false'. The jump target is popped
* from the control-flow stack as a destination.
*/
internal void AgainIfNot()
{
int x = CSPopDest();
Add(new OpcodeJumpIfNot(x - code.Count - 1));
}
}

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
class WordData : Word {
ConstData blob;
string baseBlobName;
int offset;
bool ongoingResolution;
internal WordData(T0Comp owner, string name,
ConstData blob, int offset)
: base(owner, name)
{
this.blob = blob;
this.offset = offset;
StackEffect = new SType(0, 1);
}
internal WordData(T0Comp owner, string name,
string baseBlobName, int offset)
: base(owner, name)
{
this.baseBlobName = baseBlobName;
this.offset = offset;
StackEffect = new SType(0, 1);
}
internal override void Resolve()
{
if (blob != null) {
return;
}
if (ongoingResolution) {
throw new Exception(String.Format(
"circular reference in blobs ({0})", Name));
}
ongoingResolution = true;
WordData wd = TC.Lookup(baseBlobName) as WordData;
if (wd == null) {
throw new Exception(String.Format(
"data word '{0}' based on non-data word '{1}'",
Name, baseBlobName));
}
wd.Resolve();
blob = wd.blob;
offset += wd.offset;
ongoingResolution = false;
}
internal override void Run(CPU cpu)
{
Resolve();
cpu.Push(new TValue(offset, new TPointerBlob(blob)));
}
internal override List<ConstData> GetDataBlocks()
{
Resolve();
List<ConstData> r = new List<ConstData>();
r.Add(blob);
return r;
}
internal override void GenerateCodeElements(List<CodeElement> dst)
{
Resolve();
dst.Add(new CodeElementUInt(0));
dst.Add(new CodeElementUIntInt(1, blob.Address + offset));
dst.Add(new CodeElementUInt(0));
}
}

View File

@ -0,0 +1,283 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
/*
* The implementation for interpreted words.
*/
class WordInterpreted : Word {
/*
* Get the number of local variables for this word.
*/
internal int NumLocals {
get; private set;
}
/*
* Get the sequence of opcodes for this word.
*/
internal Opcode[] Code {
get; private set;
}
string[] toResolve;
internal WordInterpreted(T0Comp owner, string name,
int numLocals, Opcode[] code, string[] toResolve)
: base(owner, name)
{
this.Code = code;
this.toResolve = toResolve;
NumLocals = numLocals;
}
internal override void Resolve()
{
if (toResolve == null) {
return;
}
for (int i = 0; i < toResolve.Length; i ++) {
string tt = toResolve[i];
if (tt == null) {
continue;
}
Code[i].ResolveTarget(TC.Lookup(tt));
}
toResolve = null;
}
internal override void Run(CPU cpu)
{
Resolve();
cpu.Enter(Code, NumLocals);
}
internal override List<Word> GetReferences()
{
Resolve();
List<Word> r = new List<Word>();
foreach (Opcode op in Code) {
Word w = op.GetReference(TC);
if (w != null) {
r.Add(w);
}
}
return r;
}
internal override List<ConstData> GetDataBlocks()
{
Resolve();
List<ConstData> r = new List<ConstData>();
foreach (Opcode op in Code) {
ConstData cd = op.GetDataBlock(TC);
if (cd != null) {
r.Add(cd);
}
}
return r;
}
internal override void GenerateCodeElements(List<CodeElement> dst)
{
Resolve();
int n = Code.Length;
CodeElement[] gcode = new CodeElement[n];
for (int i = 0; i < n; i ++) {
gcode[i] = Code[i].ToCodeElement();
}
for (int i = 0; i < n; i ++) {
Code[i].FixUp(gcode, i);
}
dst.Add(new CodeElementUInt((uint)NumLocals));
for (int i = 0; i < n; i ++) {
dst.Add(gcode[i]);
}
}
int flowAnalysis;
int maxDataStack;
int maxReturnStack;
bool MergeSA(int[] sa, int j, int c)
{
if (sa[j] == Int32.MinValue) {
sa[j] = c;
return true;
} else if (sa[j] != c) {
throw new Exception(string.Format(
"In word '{0}', offset {1}:"
+ " stack action mismatch ({2} / {3})",
Name, j, sa[j], c));
} else {
return false;
}
}
internal override void AnalyseFlow()
{
switch (flowAnalysis) {
case 0:
break;
case 1:
return;
default:
throw new Exception("recursive call detected in '"
+ Name + "'");
}
flowAnalysis = 2;
int n = Code.Length;
int[] sa = new int[n];
for (int i = 0; i < n; i ++) {
sa[i] = Int32.MinValue;
}
sa[0] = 0;
int[] toExplore = new int[n];
int tX = 0, tY = 0;
int off = 0;
int exitSA = Int32.MinValue;
int mds = 0;
int mrs = 0;
int maxDepth = 0;
for (;;) {
Opcode op = Code[off];
bool mft = op.MayFallThrough;
int c = sa[off];
int a;
if (op is OpcodeCall) {
Word w = op.GetReference(TC);
w.AnalyseFlow();
SType se = w.StackEffect;
if (!se.IsKnown) {
throw new Exception(string.Format(
"call from '{0}' to '{1}'"
+ " with unknown stack effect",
Name, w.Name));
}
if (se.NoExit) {
mft = false;
a = 0;
} else {
a = se.DataOut - se.DataIn;
}
mds = Math.Max(mds, c + w.MaxDataStack);
mrs = Math.Max(mrs, w.MaxReturnStack);
maxDepth = Math.Min(maxDepth, c - se.DataIn);
} else if (op is OpcodeRet) {
if (exitSA == Int32.MinValue) {
exitSA = c;
} else if (exitSA != c) {
throw new Exception(string.Format(
"'{0}': exit stack action"
+ " mismatch: {1} / {2}"
+ " (offset {3})",
Name, exitSA, c, off));
}
a = 0;
} else {
a = op.StackAction;
mds = Math.Max(mds, c + a);
}
c += a;
maxDepth = Math.Min(maxDepth, c);
int j = op.JumpDisp;
if (j != 0) {
j += off + 1;
toExplore[tY ++] = j;
MergeSA(sa, j, c);
}
off ++;
if (!mft || !MergeSA(sa, off, c)) {
if (tX < tY) {
off = toExplore[tX ++];
} else {
break;
}
}
}
maxDataStack = mds;
maxReturnStack = 1 + NumLocals + mrs;
/*
* TODO: see about this warning. Usage of a 'fail'
* word (that does not exit) within a 'case..endcase'
* structure will make an unreachable opcode. In a future
* version we might want to automatically remove dead
* opcodes.
for (int i = 0; i < n; i ++) {
if (sa[i] == Int32.MinValue) {
Console.WriteLine("warning: word '{0}',"
+ " offset {1}: unreachable opcode",
Name, i);
continue;
}
}
*/
SType computed;
if (exitSA == Int32.MinValue) {
computed = new SType(-maxDepth, -1);
} else {
computed = new SType(-maxDepth, -maxDepth + exitSA);
}
if (StackEffect.IsKnown) {
if (!computed.IsSubOf(StackEffect)) {
throw new Exception(string.Format(
"word '{0}':"
+ " computed stack effect {1}"
+ " does not match declared {2}",
Name, computed.ToString(),
StackEffect.ToString()));
}
} else {
StackEffect = computed;
}
flowAnalysis = 1;
}
internal override int MaxDataStack {
get {
AnalyseFlow();
return maxDataStack;
}
}
internal override int MaxReturnStack {
get {
AnalyseFlow();
return maxReturnStack;
}
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
using System;
using System.Collections.Generic;
/*
* Class for native words.
*/
class WordNative : Word {
/*
* A type for the native implementation: a method that takes a
* CPU as parameter, and returns nothing.
*/
internal delegate void NativeRun(CPU cpu);
NativeRun code;
internal WordNative(T0Comp owner, string name, NativeRun code)
: base(owner, name)
{
this.code = code;
}
internal WordNative(T0Comp owner, string name,
SType stackEffect, NativeRun code)
: this(owner, name, code)
{
StackEffect = stackEffect;
}
internal override void Run(CPU cpu)
{
code(cpu);
}
}

309
contrib/bearssl/T0/kern.t0 Normal file
View File

@ -0,0 +1,309 @@
: \ `\n parse drop ; immediate
\ This file defines the core non-native functions (mainly used for
\ parsing words, i.e. not part of the generated output). The line above
\ defines the syntax for comments.
\ Define parenthesis comments.
\ : ( `) parse drop ; immediate
: else postpone ahead 1 cs-roll postpone then ; immediate
: while postpone if 1 cs-roll ; immediate
: repeat postpone again postpone then ; immediate
: ['] ' ; immediate
: [compile] compile ; immediate
: 2drop drop drop ;
: dup2 over over ;
\ Local variables are defined with the native word '(local)'. We define
\ a helper construction that mimics what is found in Apple's Open Firmware
\ implementation. The syntax is: { a b ... ; c d ... }
\ I.e. there is an opening brace, then some names. Names appearing before
\ the semicolon are locals that are both defined and then filled with the
\ values on stack (in stack order: { a b } fills 'b' with the top-of-stack,
\ and 'a' with the value immediately below). Names appearing after the
\ semicolon are not initialized.
: __deflocal ( from_stack name -- )
dup (local) swap if
compile-local-write
else
drop
then ;
: __deflocals ( from_stack -- )
next-word
dup "}" eqstr if
2drop ret
then
dup ";" eqstr if
2drop 0 __deflocals ret
then
over __deflocals
__deflocal ;
: {
-1 __deflocals ; immediate
\ Data building words.
: data:
new-data-block next-word define-data-word ;
: hexb|
0 0 { acc z }
begin
char
dup `| = if
z if "Truncated hexadecimal byte" puts cr exitvm then
ret
then
dup 0x20 > if
hexval
z if acc 4 << + data-add8 else >acc then
z not >z
then
again ;
\ Convert hexadecimal character to number. Complain loudly if conversion
\ is not possible.
: hexval ( char -- x )
hexval-nf dup 0 < if "Not an hex digit: " puts . cr exitvm then ;
\ Convert hexadecimal character to number. If not an hexadecimal digit,
\ return -1.
: hexval-nf ( char -- x )
dup dup `0 >= swap `9 <= and if `0 - ret then
dup dup `A >= swap `F <= and if `A - 10 + ret then
dup dup `a >= swap `f <= and if `a - 10 + ret then
drop -1 ;
\ Convert decimal character to number. Complain loudly if conversion
\ is not possible.
: decval ( char -- x )
decval-nf dup 0 < if "Not a decimal digit: " puts . cr exitvm then ;
\ Convert decimal character to number. If not a decimal digit,
\ return -1.
: decval-nf ( char -- x )
dup dup `0 >= swap `9 <= and if `0 - ret then
drop -1 ;
\ Commonly used shorthands.
: 1+ 1 + ;
: 2+ 2 + ;
: 1- 1 - ;
: 2- 2 - ;
: 0= 0 = ;
: 0<> 0 <> ;
: 0< 0 < ;
: 0> 0 > ;
\ Get a 16-bit value from the constant data block. This uses big-endian
\ encoding.
: data-get16 ( addr -- x )
dup data-get8 8 << swap 1+ data-get8 + ;
\ The case..endcase construction is the equivalent of 'switch' is C.
\ Usage:
\ case
\ E1 of C1 endof
\ E2 of C2 endof
\ ...
\ CN
\ endcase
\
\ Upon entry, it considers the TOS (let's call it X). It will then evaluate
\ E1, which should yield a single value Y1; at that point, the X value is
\ still on the stack, just below Y1, and must remain untouched. The 'of'
\ word compares X with Y1; if they are equal, C1 is executed, and then
\ control jumps to after the 'endcase'. The X value is popped from the
\ stack immediately before evaluating C1.
\
\ If X and Y1 are not equal, flow proceeds to E2, to obtain a value Y2 to
\ compare with X. And so on.
\
\ If none of the 'of' clauses found a match, then CN is evaluated. When CN
\ is evaluated, the X value is on the TOS, and CN must either leave it on
\ the stack, or replace it with exactly one value; the 'endcase' word
\ expects (and drops) one value.
\
\ Implementation: this is mostly copied from ANS Forth specification,
\ although simplified a bit because we know that our control-flow stack
\ is independent of the data stack. During compilation, the number of
\ clauses is maintained on the stack; each of..endof clause really is
\ an 'if..else' that must be terminated with a matching 'then' in 'endcase'.
: case 0 ; immediate
: of 1+ postpone over postpone = postpone if postpone drop ; immediate
: endof postpone else ; immediate
: endcase
postpone drop
begin dup while 1- postpone then repeat drop ; immediate
\ A simpler and more generic "case": there is no management for a value
\ on the stack, and each test is supposed to come up with its own boolean
\ value.
: choice 0 ; immediate
: uf 1+ postpone if ; immediate
: ufnot 1+ postpone ifnot ; immediate
: enduf postpone else ; immediate
: endchoice begin dup while 1- postpone then repeat drop ; immediate
\ C implementations for native words that can be used in generated code.
add-cc: co { T0_CO(); }
add-cc: execute { T0_ENTER(ip, rp, T0_POP()); }
add-cc: drop { (void)T0_POP(); }
add-cc: dup { T0_PUSH(T0_PEEK(0)); }
add-cc: swap { T0_SWAP(); }
add-cc: over { T0_PUSH(T0_PEEK(1)); }
add-cc: rot { T0_ROT(); }
add-cc: -rot { T0_NROT(); }
add-cc: roll { T0_ROLL(T0_POP()); }
add-cc: pick { T0_PICK(T0_POP()); }
add-cc: + {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(a + b);
}
add-cc: - {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(a - b);
}
add-cc: neg {
uint32_t a = T0_POP();
T0_PUSH(-a);
}
add-cc: * {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(a * b);
}
add-cc: / {
int32_t b = T0_POPi();
int32_t a = T0_POPi();
T0_PUSHi(a / b);
}
add-cc: u/ {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(a / b);
}
add-cc: % {
int32_t b = T0_POPi();
int32_t a = T0_POPi();
T0_PUSHi(a % b);
}
add-cc: u% {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(a % b);
}
add-cc: < {
int32_t b = T0_POPi();
int32_t a = T0_POPi();
T0_PUSH(-(uint32_t)(a < b));
}
add-cc: <= {
int32_t b = T0_POPi();
int32_t a = T0_POPi();
T0_PUSH(-(uint32_t)(a <= b));
}
add-cc: > {
int32_t b = T0_POPi();
int32_t a = T0_POPi();
T0_PUSH(-(uint32_t)(a > b));
}
add-cc: >= {
int32_t b = T0_POPi();
int32_t a = T0_POPi();
T0_PUSH(-(uint32_t)(a >= b));
}
add-cc: = {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(-(uint32_t)(a == b));
}
add-cc: <> {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(-(uint32_t)(a != b));
}
add-cc: u< {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(-(uint32_t)(a < b));
}
add-cc: u<= {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(-(uint32_t)(a <= b));
}
add-cc: u> {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(-(uint32_t)(a > b));
}
add-cc: u>= {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(-(uint32_t)(a >= b));
}
add-cc: and {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(a & b);
}
add-cc: or {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(a | b);
}
add-cc: xor {
uint32_t b = T0_POP();
uint32_t a = T0_POP();
T0_PUSH(a ^ b);
}
add-cc: not {
uint32_t a = T0_POP();
T0_PUSH(~a);
}
add-cc: << {
int c = (int)T0_POPi();
uint32_t x = T0_POP();
T0_PUSH(x << c);
}
add-cc: >> {
int c = (int)T0_POPi();
int32_t x = T0_POPi();
T0_PUSHi(x >> c);
}
add-cc: u>> {
int c = (int)T0_POPi();
uint32_t x = T0_POP();
T0_PUSH(x >> c);
}
add-cc: data-get8 {
size_t addr = T0_POP();
T0_PUSH(t0_datablock[addr]);
}
add-cc: . {
extern int printf(const char *fmt, ...);
printf(" %ld", (long)T0_POPi());
}
add-cc: putc {
extern int printf(const char *fmt, ...);
printf("%c", (char)T0_POPi());
}
add-cc: puts {
extern int printf(const char *fmt, ...);
printf("%s", &t0_datablock[T0_POPi()]);
}
add-cc: cr {
extern int printf(const char *fmt, ...);
printf("\n");
}
add-cc: eqstr {
const void *b = &t0_datablock[T0_POPi()];
const void *a = &t0_datablock[T0_POPi()];
T0_PUSH(-(int32_t)(strcmp(a, b) == 0));
}

BIN
contrib/bearssl/T0Comp.exe Executable file

Binary file not shown.

View File

View File

@ -0,0 +1,69 @@
# Configuration for a native build on a generic Unix-like system.
# Build directory.
BUILD = build
# Extension for executable files.
E =
# Extension for object files.
O = .o
# Prefix for library file name.
LP = lib
# Extension for library file name.
L = .a
# Prefix for DLL file name.
DP = lib
# Extension for DLL file name.
D = .so
# Output file names can be overridden directly. By default, they are
# assembled using the prefix/extension macros defined above.
# BEARSSLLIB = libbearssl.a
# BEARSSLDLL = libbearssl.so
# BRSSL = brssl
# TESTCRYPTO = testcrypto
# TESTSPEED = testspeed
# TESTX509 = testx509
# File deletion tool.
RM = rm -f
# Directory creation tool.
MKDIR = mkdir -p
# C compiler and flags.
CC = cc
CFLAGS = -W -Wall -Os -fPIC
CCOUT = -c -o
# Static library building tool.
AR = ar
ARFLAGS = -rcs
AROUT =
# DLL building tool.
LDDLL = cc
LDDLLFLAGS = -shared
LDDLLOUT = -o
# Static linker.
LD = cc
LDFLAGS =
LDOUT = -o
# C# compiler; we assume usage of Mono.
MKT0COMP = mk$PmkT0.sh
RUNT0COMP = mono T0Comp.exe
# Set the values to 'no' to disable building of the corresponding element
# by default. Building can still be invoked with an explicit target call
# (e.g. 'make dll' to force build the DLL).
#STATICLIB = no
#DLL = no
#TOOLS = no
#TESTS = no

View File

@ -0,0 +1,12 @@
# Example configuration file for compiling on a Unix-like system with
# GCC, targeting a 32-bit output. Moreover, it enables the "LOMUL" setting
# to make the code select the "small" integer implementations (i15, m15,
# ctmul32...), which is not necessarily a good idea for performance, but
# handy for tests.
include conf/Unix.mk
BUILD = build32
CFLAGS = -W -Wall -Os -fPIC -m32 -DBR_LOMUL
LDFLAGS = -m32
LDDLLFLAGS = -shared -m32

View File

@ -0,0 +1,11 @@
# Example configuration file for compiling on a Unix-like system with
# clang as compiler instead of gcc.
# We are on a Unix system so we assume a Single Unix compatible 'make'
# utility, and Unix defaults.
include conf/Unix.mk
BUILD = bclang
CC = clang
LD = clang
LDDLL = clang

View File

@ -0,0 +1,70 @@
# Configuration for a native build on a Windows system with Visual Studio.
# Build directory.
BUILD = build
# Extension for executable files.
E = .exe
# Extension for object files.
O = .obj
# Prefix for static library file name.
LP =
# Extension for static library file name. We add an 's' so that the
# name is distinct from the 'import library' generated along with the DLL.
L = s.lib
# Prefix for DLL file name.
DP =
# Extension for DLL file name.
D = .dll
# Output file names can be overridden directly. By default, they are
# assembled using the prefix/extension macros defined above.
# BEARSSLLIB = bearssls.lib
# BEARSSLDLL = bearssl.dll
# BRSSL = brssl.exe
# TESTCRYPTO = testcrypto.exe
# TESTSPEED = testspeed.exe
# TESTX509 = testx509.exe
# File deletion tool.
RM = del /Q
# Directory creation tool.
MKDIR = mkdir
# C compiler and flags.
CC = cl
CFLAGS = -nologo -W2 -O2
CCOUT = -c -Fo
# Static library building tool.
AR = lib
ARFLAGS = -nologo
AROUT = -out:
# DLL building tool.
LDDLL = cl
LDDLLFLAGS = -nologo -LD -MT
LDDLLOUT = -Fe
# Static linker.
LD = cl
LDFLAGS = -nologo
LDOUT = -Fe
# C# compiler.
MKT0COMP = mk$PmkT0.cmd
RUNT0COMP = T0Comp.exe
# Set the values to 'no' to disable building of the corresponding element
# by default. Building can still be invoked with an explicit target call
# (e.g. 'make dll' to force build the DLL).
#STATICLIB = no
#DLL = no
#TOOLS = no
#TESTS = no

View File

@ -0,0 +1,20 @@
# Example configuration file for compiling for an Atmel SAM D20 Xplained
# Pro evaluation kit, on a Unix-like system, with a GNU toolchain.
# We are on a Unix system so we assume a Single Unix compatible 'make'
# utility, and Unix defaults.
include conf/Unix.mk
# We override the build directory.
BUILD = samd20
# C compiler, linker, and static library builder.
CC = arm-none-eabi-gcc
CFLAGS = -W -Wall -Os -mthumb -ffunction-sections -fdata-sections -mcpu=cortex-m0plus -DBR_ARMEL_CORTEXM_GCC
LD = arm-none-eabi-gcc
AR = arm-none-eabi-ar
# We compile only the static library.
DLL = no
TOOLS = no
TESTS = no

View File

@ -0,0 +1,170 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
#ifndef BR_BEARSSL_H__
#define BR_BEARSSL_H__
#include <stddef.h>
#include <stdint.h>
/** \mainpage BearSSL API
*
* # API Layout
*
* The functions and structures defined by the BearSSL API are located
* in various header files:
*
* | Header file | Elements |
* | :-------------- | :------------------------------------------------ |
* | bearssl_hash.h | Hash functions |
* | bearssl_hmac.h | HMAC |
* | bearssl_kdf.h | Key Derivation Functions |
* | bearssl_rand.h | Pseudorandom byte generators |
* | bearssl_prf.h | PRF implementations (for SSL/TLS) |
* | bearssl_block.h | Symmetric encryption |
* | bearssl_aead.h | AEAD algorithms (combined encryption + MAC) |
* | bearssl_rsa.h | RSA encryption and signatures |
* | bearssl_ec.h | Elliptic curves support (including ECDSA) |
* | bearssl_ssl.h | SSL/TLS engine interface |
* | bearssl_x509.h | X.509 certificate decoding and validation |
* | bearssl_pem.h | Base64/PEM decoding support functions |
*
* Applications using BearSSL are supposed to simply include `bearssl.h`
* as follows:
*
* #include <bearssl.h>
*
* The `bearssl.h` file itself includes all the other header files. It is
* possible to include specific header files, but it has no practical
* advantage for the application. The API is separated into separate
* header files only for documentation convenience.
*
*
* # Conventions
*
* ## MUST and SHALL
*
* In all descriptions, the usual "MUST", "SHALL", "MAY",... terminology
* is used. Failure to meet requirements expressed with a "MUST" or
* "SHALL" implies undefined behaviour, which means that segmentation
* faults, buffer overflows, and other similar adverse events, may occur.
*
* In general, BearSSL is not very forgiving of programming errors, and
* does not include much failsafes or error reporting when the problem
* does not arise from external transient conditions, and can be fixed
* only in the application code. This is done so in order to make the
* total code footprint lighter.
*
*
* ## `NULL` values
*
* Function parameters with a pointer type shall not be `NULL` unless
* explicitly authorised by the documentation. As an exception, when
* the pointer aims at a sequence of bytes and is accompanied with
* a length parameter, and the length is zero (meaning that there is
* no byte at all to retrieve), then the pointer may be `NULL` even if
* not explicitly allowed.
*
*
* ## Memory Allocation
*
* BearSSL does not perform dynamic memory allocation. This implies that
* for any functionality that requires a non-transient state, the caller
* is responsible for allocating the relevant context structure. Such
* allocation can be done in any appropriate area, including static data
* segments, the heap, and the stack, provided that proper alignment is
* respected. The header files define these context structures
* (including size and contents), so the C compiler should handle
* alignment automatically.
*
* Since there is no dynamic resource allocation, there is also nothing to
* release. When the calling code is done with a BearSSL feature, it
* may simple release the context structures it allocated itself, with
* no "close function" to call. If the context structures were allocated
* on the stack (as local variables), then even that release operation is
* implicit.
*
*
* ## Structure Contents
*
* Except when explicitly indicated, structure contents are opaque: they
* are included in the header files so that calling code may know the
* structure sizes and alignment requirements, but callers SHALL NOT
* access individual fields directly. For fields that are supposed to
* be read from or written to, the API defines accessor functions (the
* simplest of these accessor functions are defined as `static inline`
* functions, and the C compiler will optimise them away).
*
*
* # API Usage
*
* BearSSL usage for running a SSL/TLS client or server is described
* on the [BearSSL Web site](https://www.bearssl.org/api1.html). The
* BearSSL source archive also comes with sample code.
*/
#include "bearssl_hash.h"
#include "bearssl_hmac.h"
#include "bearssl_kdf.h"
#include "bearssl_rand.h"
#include "bearssl_prf.h"
#include "bearssl_block.h"
#include "bearssl_aead.h"
#include "bearssl_rsa.h"
#include "bearssl_ec.h"
#include "bearssl_ssl.h"
#include "bearssl_x509.h"
#include "bearssl_pem.h"
/** \brief Type for a configuration option.
*
* A "configuration option" is a value that is selected when the BearSSL
* library itself is compiled. Most options are boolean; their value is
* then either 1 (option is enabled) or 0 (option is disabled). Some
* values have other integer values. Option names correspond to macro
* names. Some of the options can be explicitly set in the internal
* `"config.h"` file.
*/
typedef struct {
/** \brief Configurable option name. */
const char *name;
/** \brief Configurable option value. */
long value;
} br_config_option;
/** \brief Get configuration report.
*
* This function returns compiled configuration options, each as a
* 'long' value. Names match internal macro names, in particular those
* that can be set in the `"config.h"` inner file. For boolean options,
* the numerical value is 1 if enabled, 0 if disabled. For maximum
* key sizes, values are expressed in bits.
*
* The returned array is terminated by an entry whose `name` is `NULL`.
*
* \return the configuration report.
*/
const br_config_option *br_get_config(void);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,967 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
#ifndef BR_BEARSSL_EC_H__
#define BR_BEARSSL_EC_H__
#include <stddef.h>
#include <stdint.h>
#include "bearssl_rand.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file bearssl_ec.h
*
* # Elliptic Curves
*
* This file documents the EC implementations provided with BearSSL, and
* ECDSA.
*
* ## Elliptic Curve API
*
* Only "named curves" are supported. Each EC implementation supports
* one or several named curves, identified by symbolic identifiers.
* These identifiers are small integers, that correspond to the values
* registered by the
* [IANA](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8).
*
* Since all currently defined elliptic curve identifiers are in the 0..31
* range, it is convenient to encode support of some curves in a 32-bit
* word, such that bit x corresponds to curve of identifier x.
*
* An EC implementation is incarnated by a `br_ec_impl` instance, that
* offers the following fields:
*
* - `supported_curves`
*
* A 32-bit word that documents the identifiers of the curves supported
* by this implementation.
*
* - `generator()`
*
* Callback method that returns a pointer to the conventional generator
* point for that curve.
*
* - `order()`
*
* Callback method that returns a pointer to the subgroup order for
* that curve. That value uses unsigned big-endian encoding.
*
* - `xoff()`
*
* Callback method that returns the offset and length of the X
* coordinate in an encoded point.
*
* - `mul()`
*
* Multiply a curve point with an integer.
*
* - `mulgen()`
*
* Multiply the curve generator with an integer. This may be faster
* than the generic `mul()`.
*
* - `muladd()`
*
* Multiply two curve points by two integers, and return the sum of
* the two products.
*
* All curve points are represented in uncompressed format. The `mul()`
* and `muladd()` methods take care to validate that the provided points
* are really part of the relevant curve subgroup.
*
* For all point multiplication functions, the following holds:
*
* - Functions validate that the provided points are valid members
* of the relevant curve subgroup. An error is reported if that is
* not the case.
*
* - Processing is constant-time, even if the point operands are not
* valid. This holds for both the source and resulting points, and
* the multipliers (integers). Only the byte length of the provided
* multiplier arrays (not their actual value length in bits) may
* leak through timing-based side channels.
*
* - The multipliers (integers) MUST be lower than the subgroup order.
* If this property is not met, then the result is indeterminate,
* but an error value is not ncessearily returned.
*
*
* ## ECDSA
*
* ECDSA signatures have two standard formats, called "raw" and "asn1".
* Internally, such a signature is a pair of modular integers `(r,s)`.
* The "raw" format is the concatenation of the unsigned big-endian
* encodings of these two integers, possibly left-padded with zeros so
* that they have the same encoded length. The "asn1" format is the
* DER encoding of an ASN.1 structure that contains the two integer
* values:
*
* ECDSASignature ::= SEQUENCE {
* r INTEGER,
* s INTEGER
* }
*
* In general, in all of X.509 and SSL/TLS, the "asn1" format is used.
* BearSSL offers ECDSA implementations for both formats; conversion
* functions between the two formats are also provided. Conversion of a
* "raw" format signature into "asn1" may enlarge a signature by no more
* than 9 bytes for all supported curves; conversely, conversion of an
* "asn1" signature to "raw" may expand the signature but the "raw"
* length will never be more than twice the length of the "asn1" length
* (and usually it will be shorter).
*
* Note that for a given signature, the "raw" format is not fully
* deterministic, in that it does not enforce a minimal common length.
*/
/*
* Standard curve ID. These ID are equal to the assigned numerical
* identifiers assigned to these curves for TLS:
* http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
*/
/** \brief Identifier for named curve sect163k1. */
#define BR_EC_sect163k1 1
/** \brief Identifier for named curve sect163r1. */
#define BR_EC_sect163r1 2
/** \brief Identifier for named curve sect163r2. */
#define BR_EC_sect163r2 3
/** \brief Identifier for named curve sect193r1. */
#define BR_EC_sect193r1 4
/** \brief Identifier for named curve sect193r2. */
#define BR_EC_sect193r2 5
/** \brief Identifier for named curve sect233k1. */
#define BR_EC_sect233k1 6
/** \brief Identifier for named curve sect233r1. */
#define BR_EC_sect233r1 7
/** \brief Identifier for named curve sect239k1. */
#define BR_EC_sect239k1 8
/** \brief Identifier for named curve sect283k1. */
#define BR_EC_sect283k1 9
/** \brief Identifier for named curve sect283r1. */
#define BR_EC_sect283r1 10
/** \brief Identifier for named curve sect409k1. */
#define BR_EC_sect409k1 11
/** \brief Identifier for named curve sect409r1. */
#define BR_EC_sect409r1 12
/** \brief Identifier for named curve sect571k1. */
#define BR_EC_sect571k1 13
/** \brief Identifier for named curve sect571r1. */
#define BR_EC_sect571r1 14
/** \brief Identifier for named curve secp160k1. */
#define BR_EC_secp160k1 15
/** \brief Identifier for named curve secp160r1. */
#define BR_EC_secp160r1 16
/** \brief Identifier for named curve secp160r2. */
#define BR_EC_secp160r2 17
/** \brief Identifier for named curve secp192k1. */
#define BR_EC_secp192k1 18
/** \brief Identifier for named curve secp192r1. */
#define BR_EC_secp192r1 19
/** \brief Identifier for named curve secp224k1. */
#define BR_EC_secp224k1 20
/** \brief Identifier for named curve secp224r1. */
#define BR_EC_secp224r1 21
/** \brief Identifier for named curve secp256k1. */
#define BR_EC_secp256k1 22
/** \brief Identifier for named curve secp256r1. */
#define BR_EC_secp256r1 23
/** \brief Identifier for named curve secp384r1. */
#define BR_EC_secp384r1 24
/** \brief Identifier for named curve secp521r1. */
#define BR_EC_secp521r1 25
/** \brief Identifier for named curve brainpoolP256r1. */
#define BR_EC_brainpoolP256r1 26
/** \brief Identifier for named curve brainpoolP384r1. */
#define BR_EC_brainpoolP384r1 27
/** \brief Identifier for named curve brainpoolP512r1. */
#define BR_EC_brainpoolP512r1 28
/** \brief Identifier for named curve Curve25519. */
#define BR_EC_curve25519 29
/** \brief Identifier for named curve Curve448. */
#define BR_EC_curve448 30
/**
* \brief Structure for an EC public key.
*/
typedef struct {
/** \brief Identifier for the curve used by this key. */
int curve;
/** \brief Public curve point (uncompressed format). */
unsigned char *q;
/** \brief Length of public curve point (in bytes). */
size_t qlen;
} br_ec_public_key;
/**
* \brief Structure for an EC private key.
*
* The private key is an integer modulo the curve subgroup order. The
* encoding below tolerates extra leading zeros. In general, it is
* recommended that the private key has the same length as the curve
* subgroup order.
*/
typedef struct {
/** \brief Identifier for the curve used by this key. */
int curve;
/** \brief Private key (integer, unsigned big-endian encoding). */
unsigned char *x;
/** \brief Private key length (in bytes). */
size_t xlen;
} br_ec_private_key;
/**
* \brief Type for an EC implementation.
*/
typedef struct {
/**
* \brief Supported curves.
*
* This word is a bitfield: bit `x` is set if the curve of ID `x`
* is supported. E.g. an implementation supporting both NIST P-256
* (secp256r1, ID 23) and NIST P-384 (secp384r1, ID 24) will have
* value `0x01800000` in this field.
*/
uint32_t supported_curves;
/**
* \brief Get the conventional generator.
*
* This function returns the conventional generator (encoded
* curve point) for the specified curve. This function MUST NOT
* be called if the curve is not supported.
*
* \param curve curve identifier.
* \param len receiver for the encoded generator length (in bytes).
* \return the encoded generator.
*/
const unsigned char *(*generator)(int curve, size_t *len);
/**
* \brief Get the subgroup order.
*
* This function returns the order of the subgroup generated by
* the conventional generator, for the specified curve. Unsigned
* big-endian encoding is used. This function MUST NOT be called
* if the curve is not supported.
*
* \param curve curve identifier.
* \param len receiver for the encoded order length (in bytes).
* \return the encoded order.
*/
const unsigned char *(*order)(int curve, size_t *len);
/**
* \brief Get the offset and length for the X coordinate.
*
* This function returns the offset and length (in bytes) of
* the X coordinate in an encoded non-zero point.
*
* \param curve curve identifier.
* \param len receiver for the X coordinate length (in bytes).
* \return the offset for the X coordinate (in bytes).
*/
size_t (*xoff)(int curve, size_t *len);
/**
* \brief Multiply a curve point by an integer.
*
* The source point is provided in array `G` (of size `Glen` bytes);
* the multiplication result is written over it. The multiplier
* `x` (of size `xlen` bytes) uses unsigned big-endian encoding.
*
* Rules:
*
* - The specified curve MUST be supported.
*
* - The source point must be a valid point on the relevant curve
* subgroup (and not the "point at infinity" either). If this is
* not the case, then this function returns an error (0).
*
* - The multiplier integer MUST be non-zero and less than the
* curve subgroup order. If this property does not hold, then
* the result is indeterminate and an error code is not
* guaranteed.
*
* Returned value is 1 on success, 0 on error. On error, the
* contents of `G` are indeterminate.
*
* \param G point to multiply.
* \param Glen length of the encoded point (in bytes).
* \param x multiplier (unsigned big-endian).
* \param xlen multiplier length (in bytes).
* \param curve curve identifier.
* \return 1 on success, 0 on error.
*/
uint32_t (*mul)(unsigned char *G, size_t Glen,
const unsigned char *x, size_t xlen, int curve);
/**
* \brief Multiply the generator by an integer.
*
* The multiplier MUST be non-zero and less than the curve
* subgroup order. Results are indeterminate if this property
* does not hold.
*
* \param R output buffer for the point.
* \param x multiplier (unsigned big-endian).
* \param xlen multiplier length (in bytes).
* \param curve curve identifier.
* \return encoded result point length (in bytes).
*/
size_t (*mulgen)(unsigned char *R,
const unsigned char *x, size_t xlen, int curve);
/**
* \brief Multiply two points by two integers and add the
* results.
*
* The point `x*A + y*B` is computed and written back in the `A`
* array.
*
* Rules:
*
* - The specified curve MUST be supported.
*
* - The source points (`A` and `B`) must be valid points on
* the relevant curve subgroup (and not the "point at
* infinity" either). If this is not the case, then this
* function returns an error (0).
*
* - If the `B` pointer is `NULL`, then the conventional
* subgroup generator is used. With some implementations,
* this may be faster than providing a pointer to the
* generator.
*
* - The multiplier integers (`x` and `y`) MUST be non-zero
* and less than the curve subgroup order. If either integer
* is zero, then an error is reported, but if one of them is
* not lower than the subgroup order, then the result is
* indeterminate and an error code is not guaranteed.
*
* - If the final result is the point at infinity, then an
* error is returned.
*
* Returned value is 1 on success, 0 on error. On error, the
* contents of `A` are indeterminate.
*
* \param A first point to multiply.
* \param B second point to multiply (`NULL` for the generator).
* \param len common length of the encoded points (in bytes).
* \param x multiplier for `A` (unsigned big-endian).
* \param xlen length of multiplier for `A` (in bytes).
* \param y multiplier for `A` (unsigned big-endian).
* \param ylen length of multiplier for `A` (in bytes).
* \param curve curve identifier.
* \return 1 on success, 0 on error.
*/
uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len,
const unsigned char *x, size_t xlen,
const unsigned char *y, size_t ylen, int curve);
} br_ec_impl;
/**
* \brief EC implementation "i31".
*
* This implementation internally uses generic code for modular integers,
* with a representation as sequences of 31-bit words. It supports secp256r1,
* secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
*/
extern const br_ec_impl br_ec_prime_i31;
/**
* \brief EC implementation "i15".
*
* This implementation internally uses generic code for modular integers,
* with a representation as sequences of 15-bit words. It supports secp256r1,
* secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
*/
extern const br_ec_impl br_ec_prime_i15;
/**
* \brief EC implementation "m15" for P-256.
*
* This implementation uses specialised code for curve secp256r1 (also
* known as NIST P-256), with optional Karatsuba decomposition, and fast
* modular reduction thanks to the field modulus special format. Only
* 32-bit multiplications are used (with 32-bit results, not 64-bit).
*/
extern const br_ec_impl br_ec_p256_m15;
/**
* \brief EC implementation "m31" for P-256.
*
* This implementation uses specialised code for curve secp256r1 (also
* known as NIST P-256), relying on multiplications of 31-bit values
* (MUL31).
*/
extern const br_ec_impl br_ec_p256_m31;
/**
* \brief EC implementation "m62" (specialised code) for P-256.
*
* This implementation uses custom code relying on multiplication of
* integers up to 64 bits, with a 128-bit result. This implementation is
* defined only on platforms that offer the 64x64->128 multiplication
* support; use `br_ec_p256_m62_get()` to dynamically obtain a pointer
* to that implementation.
*/
extern const br_ec_impl br_ec_p256_m62;
/**
* \brief Get the "m62" implementation of P-256, if available.
*
* \return the implementation, or 0.
*/
const br_ec_impl *br_ec_p256_m62_get(void);
/**
* \brief EC implementation "m64" (specialised code) for P-256.
*
* This implementation uses custom code relying on multiplication of
* integers up to 64 bits, with a 128-bit result. This implementation is
* defined only on platforms that offer the 64x64->128 multiplication
* support; use `br_ec_p256_m64_get()` to dynamically obtain a pointer
* to that implementation.
*/
extern const br_ec_impl br_ec_p256_m64;
/**
* \brief Get the "m64" implementation of P-256, if available.
*
* \return the implementation, or 0.
*/
const br_ec_impl *br_ec_p256_m64_get(void);
/**
* \brief EC implementation "i15" (generic code) for Curve25519.
*
* This implementation uses the generic code for modular integers (with
* 15-bit words) to support Curve25519. Due to the specificities of the
* curve definition, the following applies:
*
* - `muladd()` is not implemented (the function returns 0 systematically).
* - `order()` returns 2^255-1, since the point multiplication algorithm
* accepts any 32-bit integer as input (it clears the top bit and low
* three bits systematically).
*/
extern const br_ec_impl br_ec_c25519_i15;
/**
* \brief EC implementation "i31" (generic code) for Curve25519.
*
* This implementation uses the generic code for modular integers (with
* 31-bit words) to support Curve25519. Due to the specificities of the
* curve definition, the following applies:
*
* - `muladd()` is not implemented (the function returns 0 systematically).
* - `order()` returns 2^255-1, since the point multiplication algorithm
* accepts any 32-bit integer as input (it clears the top bit and low
* three bits systematically).
*/
extern const br_ec_impl br_ec_c25519_i31;
/**
* \brief EC implementation "m15" (specialised code) for Curve25519.
*
* This implementation uses custom code relying on multiplication of
* integers up to 15 bits. Due to the specificities of the curve
* definition, the following applies:
*
* - `muladd()` is not implemented (the function returns 0 systematically).
* - `order()` returns 2^255-1, since the point multiplication algorithm
* accepts any 32-bit integer as input (it clears the top bit and low
* three bits systematically).
*/
extern const br_ec_impl br_ec_c25519_m15;
/**
* \brief EC implementation "m31" (specialised code) for Curve25519.
*
* This implementation uses custom code relying on multiplication of
* integers up to 31 bits. Due to the specificities of the curve
* definition, the following applies:
*
* - `muladd()` is not implemented (the function returns 0 systematically).
* - `order()` returns 2^255-1, since the point multiplication algorithm
* accepts any 32-bit integer as input (it clears the top bit and low
* three bits systematically).
*/
extern const br_ec_impl br_ec_c25519_m31;
/**
* \brief EC implementation "m62" (specialised code) for Curve25519.
*
* This implementation uses custom code relying on multiplication of
* integers up to 62 bits, with a 124-bit result. This implementation is
* defined only on platforms that offer the 64x64->128 multiplication
* support; use `br_ec_c25519_m62_get()` to dynamically obtain a pointer
* to that implementation. Due to the specificities of the curve
* definition, the following applies:
*
* - `muladd()` is not implemented (the function returns 0 systematically).
* - `order()` returns 2^255-1, since the point multiplication algorithm
* accepts any 32-bit integer as input (it clears the top bit and low
* three bits systematically).
*/
extern const br_ec_impl br_ec_c25519_m62;
/**
* \brief Get the "m62" implementation of Curve25519, if available.
*
* \return the implementation, or 0.
*/
const br_ec_impl *br_ec_c25519_m62_get(void);
/**
* \brief EC implementation "m64" (specialised code) for Curve25519.
*
* This implementation uses custom code relying on multiplication of
* integers up to 64 bits, with a 128-bit result. This implementation is
* defined only on platforms that offer the 64x64->128 multiplication
* support; use `br_ec_c25519_m64_get()` to dynamically obtain a pointer
* to that implementation. Due to the specificities of the curve
* definition, the following applies:
*
* - `muladd()` is not implemented (the function returns 0 systematically).
* - `order()` returns 2^255-1, since the point multiplication algorithm
* accepts any 32-bit integer as input (it clears the top bit and low
* three bits systematically).
*/
extern const br_ec_impl br_ec_c25519_m64;
/**
* \brief Get the "m64" implementation of Curve25519, if available.
*
* \return the implementation, or 0.
*/
const br_ec_impl *br_ec_c25519_m64_get(void);
/**
* \brief Aggregate EC implementation "m15".
*
* This implementation is a wrapper for:
*
* - `br_ec_c25519_m15` for Curve25519
* - `br_ec_p256_m15` for NIST P-256
* - `br_ec_prime_i15` for other curves (NIST P-384 and NIST-P512)
*/
extern const br_ec_impl br_ec_all_m15;
/**
* \brief Aggregate EC implementation "m31".
*
* This implementation is a wrapper for:
*
* - `br_ec_c25519_m31` for Curve25519
* - `br_ec_p256_m31` for NIST P-256
* - `br_ec_prime_i31` for other curves (NIST P-384 and NIST-P512)
*/
extern const br_ec_impl br_ec_all_m31;
/**
* \brief Get the "default" EC implementation for the current system.
*
* This returns a pointer to the preferred implementation on the
* current system.
*
* \return the default EC implementation.
*/
const br_ec_impl *br_ec_get_default(void);
/**
* \brief Convert a signature from "raw" to "asn1".
*
* Conversion is done "in place" and the new length is returned.
* Conversion may enlarge the signature, but by no more than 9 bytes at
* most. On error, 0 is returned (error conditions include an odd raw
* signature length, or an oversized integer).
*
* \param sig signature to convert.
* \param sig_len signature length (in bytes).
* \return the new signature length, or 0 on error.
*/
size_t br_ecdsa_raw_to_asn1(void *sig, size_t sig_len);
/**
* \brief Convert a signature from "asn1" to "raw".
*
* Conversion is done "in place" and the new length is returned.
* Conversion may enlarge the signature, but the new signature length
* will be less than twice the source length at most. On error, 0 is
* returned (error conditions include an invalid ASN.1 structure or an
* oversized integer).
*
* \param sig signature to convert.
* \param sig_len signature length (in bytes).
* \return the new signature length, or 0 on error.
*/
size_t br_ecdsa_asn1_to_raw(void *sig, size_t sig_len);
/**
* \brief Type for an ECDSA signer function.
*
* A pointer to the EC implementation is provided. The hash value is
* assumed to have the length inferred from the designated hash function
* class.
*
* Signature is written in the buffer pointed to by `sig`, and the length
* (in bytes) is returned. On error, nothing is written in the buffer,
* and 0 is returned. This function returns 0 if the specified curve is
* not supported by the provided EC implementation.
*
* The signature format is either "raw" or "asn1", depending on the
* implementation; maximum length is predictable from the implemented
* curve:
*
* | curve | raw | asn1 |
* | :--------- | --: | ---: |
* | NIST P-256 | 64 | 72 |
* | NIST P-384 | 96 | 104 |
* | NIST P-521 | 132 | 139 |
*
* \param impl EC implementation to use.
* \param hf hash function used to process the data.
* \param hash_value signed data (hashed).
* \param sk EC private key.
* \param sig destination buffer.
* \return the signature length (in bytes), or 0 on error.
*/
typedef size_t (*br_ecdsa_sign)(const br_ec_impl *impl,
const br_hash_class *hf, const void *hash_value,
const br_ec_private_key *sk, void *sig);
/**
* \brief Type for an ECDSA signature verification function.
*
* A pointer to the EC implementation is provided. The hashed value,
* computed over the purportedly signed data, is also provided with
* its length.
*
* The signature format is either "raw" or "asn1", depending on the
* implementation.
*
* Returned value is 1 on success (valid signature), 0 on error. This
* function returns 0 if the specified curve is not supported by the
* provided EC implementation.
*
* \param impl EC implementation to use.
* \param hash signed data (hashed).
* \param hash_len hash value length (in bytes).
* \param pk EC public key.
* \param sig signature.
* \param sig_len signature length (in bytes).
* \return 1 on success, 0 on error.
*/
typedef uint32_t (*br_ecdsa_vrfy)(const br_ec_impl *impl,
const void *hash, size_t hash_len,
const br_ec_public_key *pk, const void *sig, size_t sig_len);
/**
* \brief ECDSA signature generator, "i31" implementation, "asn1" format.
*
* \see br_ecdsa_sign()
*
* \param impl EC implementation to use.
* \param hf hash function used to process the data.
* \param hash_value signed data (hashed).
* \param sk EC private key.
* \param sig destination buffer.
* \return the signature length (in bytes), or 0 on error.
*/
size_t br_ecdsa_i31_sign_asn1(const br_ec_impl *impl,
const br_hash_class *hf, const void *hash_value,
const br_ec_private_key *sk, void *sig);
/**
* \brief ECDSA signature generator, "i31" implementation, "raw" format.
*
* \see br_ecdsa_sign()
*
* \param impl EC implementation to use.
* \param hf hash function used to process the data.
* \param hash_value signed data (hashed).
* \param sk EC private key.
* \param sig destination buffer.
* \return the signature length (in bytes), or 0 on error.
*/
size_t br_ecdsa_i31_sign_raw(const br_ec_impl *impl,
const br_hash_class *hf, const void *hash_value,
const br_ec_private_key *sk, void *sig);
/**
* \brief ECDSA signature verifier, "i31" implementation, "asn1" format.
*
* \see br_ecdsa_vrfy()
*
* \param impl EC implementation to use.
* \param hash signed data (hashed).
* \param hash_len hash value length (in bytes).
* \param pk EC public key.
* \param sig signature.
* \param sig_len signature length (in bytes).
* \return 1 on success, 0 on error.
*/
uint32_t br_ecdsa_i31_vrfy_asn1(const br_ec_impl *impl,
const void *hash, size_t hash_len,
const br_ec_public_key *pk, const void *sig, size_t sig_len);
/**
* \brief ECDSA signature verifier, "i31" implementation, "raw" format.
*
* \see br_ecdsa_vrfy()
*
* \param impl EC implementation to use.
* \param hash signed data (hashed).
* \param hash_len hash value length (in bytes).
* \param pk EC public key.
* \param sig signature.
* \param sig_len signature length (in bytes).
* \return 1 on success, 0 on error.
*/
uint32_t br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl,
const void *hash, size_t hash_len,
const br_ec_public_key *pk, const void *sig, size_t sig_len);
/**
* \brief ECDSA signature generator, "i15" implementation, "asn1" format.
*
* \see br_ecdsa_sign()
*
* \param impl EC implementation to use.
* \param hf hash function used to process the data.
* \param hash_value signed data (hashed).
* \param sk EC private key.
* \param sig destination buffer.
* \return the signature length (in bytes), or 0 on error.
*/
size_t br_ecdsa_i15_sign_asn1(const br_ec_impl *impl,
const br_hash_class *hf, const void *hash_value,
const br_ec_private_key *sk, void *sig);
/**
* \brief ECDSA signature generator, "i15" implementation, "raw" format.
*
* \see br_ecdsa_sign()
*
* \param impl EC implementation to use.
* \param hf hash function used to process the data.
* \param hash_value signed data (hashed).
* \param sk EC private key.
* \param sig destination buffer.
* \return the signature length (in bytes), or 0 on error.
*/
size_t br_ecdsa_i15_sign_raw(const br_ec_impl *impl,
const br_hash_class *hf, const void *hash_value,
const br_ec_private_key *sk, void *sig);
/**
* \brief ECDSA signature verifier, "i15" implementation, "asn1" format.
*
* \see br_ecdsa_vrfy()
*
* \param impl EC implementation to use.
* \param hash signed data (hashed).
* \param hash_len hash value length (in bytes).
* \param pk EC public key.
* \param sig signature.
* \param sig_len signature length (in bytes).
* \return 1 on success, 0 on error.
*/
uint32_t br_ecdsa_i15_vrfy_asn1(const br_ec_impl *impl,
const void *hash, size_t hash_len,
const br_ec_public_key *pk, const void *sig, size_t sig_len);
/**
* \brief ECDSA signature verifier, "i15" implementation, "raw" format.
*
* \see br_ecdsa_vrfy()
*
* \param impl EC implementation to use.
* \param hash signed data (hashed).
* \param hash_len hash value length (in bytes).
* \param pk EC public key.
* \param sig signature.
* \param sig_len signature length (in bytes).
* \return 1 on success, 0 on error.
*/
uint32_t br_ecdsa_i15_vrfy_raw(const br_ec_impl *impl,
const void *hash, size_t hash_len,
const br_ec_public_key *pk, const void *sig, size_t sig_len);
/**
* \brief Get "default" ECDSA implementation (signer, asn1 format).
*
* This returns the preferred implementation of ECDSA signature generation
* ("asn1" output format) on the current system.
*
* \return the default implementation.
*/
br_ecdsa_sign br_ecdsa_sign_asn1_get_default(void);
/**
* \brief Get "default" ECDSA implementation (signer, raw format).
*
* This returns the preferred implementation of ECDSA signature generation
* ("raw" output format) on the current system.
*
* \return the default implementation.
*/
br_ecdsa_sign br_ecdsa_sign_raw_get_default(void);
/**
* \brief Get "default" ECDSA implementation (verifier, asn1 format).
*
* This returns the preferred implementation of ECDSA signature verification
* ("asn1" output format) on the current system.
*
* \return the default implementation.
*/
br_ecdsa_vrfy br_ecdsa_vrfy_asn1_get_default(void);
/**
* \brief Get "default" ECDSA implementation (verifier, raw format).
*
* This returns the preferred implementation of ECDSA signature verification
* ("raw" output format) on the current system.
*
* \return the default implementation.
*/
br_ecdsa_vrfy br_ecdsa_vrfy_raw_get_default(void);
/**
* \brief Maximum size for EC private key element buffer.
*
* This is the largest number of bytes that `br_ec_keygen()` may need or
* ever return.
*/
#define BR_EC_KBUF_PRIV_MAX_SIZE 72
/**
* \brief Maximum size for EC public key element buffer.
*
* This is the largest number of bytes that `br_ec_compute_public()` may
* need or ever return.
*/
#define BR_EC_KBUF_PUB_MAX_SIZE 145
/**
* \brief Generate a new EC private key.
*
* If the specified `curve` is not supported by the elliptic curve
* implementation (`impl`), then this function returns zero.
*
* The `sk` structure fields are set to the new private key data. In
* particular, `sk.x` is made to point to the provided key buffer (`kbuf`),
* in which the actual private key data is written. That buffer is assumed
* to be large enough. The `BR_EC_KBUF_PRIV_MAX_SIZE` defines the maximum
* size for all supported curves.
*
* The number of bytes used in `kbuf` is returned. If `kbuf` is `NULL`, then
* the private key is not actually generated, and `sk` may also be `NULL`;
* the minimum length for `kbuf` is still computed and returned.
*
* If `sk` is `NULL` but `kbuf` is not `NULL`, then the private key is
* still generated and stored in `kbuf`.
*
* \param rng_ctx source PRNG context (already initialized).
* \param impl the elliptic curve implementation.
* \param sk the private key structure to fill, or `NULL`.
* \param kbuf the key element buffer, or `NULL`.
* \param curve the curve identifier.
* \return the key data length (in bytes), or zero.
*/
size_t br_ec_keygen(const br_prng_class **rng_ctx,
const br_ec_impl *impl, br_ec_private_key *sk,
void *kbuf, int curve);
/**
* \brief Compute EC public key from EC private key.
*
* This function uses the provided elliptic curve implementation (`impl`)
* to compute the public key corresponding to the private key held in `sk`.
* The public key point is written into `kbuf`, which is then linked from
* the `*pk` structure. The size of the public key point, i.e. the number
* of bytes used in `kbuf`, is returned.
*
* If `kbuf` is `NULL`, then the public key point is NOT computed, and
* the public key structure `*pk` is unmodified (`pk` may be `NULL` in
* that case). The size of the public key point is still returned.
*
* If `pk` is `NULL` but `kbuf` is not `NULL`, then the public key
* point is computed and stored in `kbuf`, and its size is returned.
*
* If the curve used by the private key is not supported by the curve
* implementation, then this function returns zero.
*
* The private key MUST be valid. An off-range private key value is not
* necessarily detected, and leads to unpredictable results.
*
* \param impl the elliptic curve implementation.
* \param pk the public key structure to fill (or `NULL`).
* \param kbuf the public key point buffer (or `NULL`).
* \param sk the source private key.
* \return the public key point length (in bytes), or zero.
*/
size_t br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk,
void *kbuf, const br_ec_private_key *sk);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,241 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
#ifndef BR_BEARSSL_HMAC_H__
#define BR_BEARSSL_HMAC_H__
#include <stddef.h>
#include <stdint.h>
#include "bearssl_hash.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file bearssl_hmac.h
*
* # HMAC
*
* HMAC is initialized with a key and an underlying hash function; it
* then fills a "key context". That context contains the processed
* key.
*
* With the key context, a HMAC context can be initialized to process
* the input bytes and obtain the MAC output. The key context is not
* modified during that process, and can be reused.
*
* IMPORTANT: HMAC shall be used only with functions that have the
* following properties:
*
* - hash output size does not exceed 64 bytes;
* - hash internal state size does not exceed 64 bytes;
* - internal block length is a power of 2 between 16 and 256 bytes.
*/
/**
* \brief HMAC key context.
*
* The HMAC key context is initialised with a hash function implementation
* and a secret key. Contents are opaque (callers should not access them
* directly). The caller is responsible for allocating the context where
* appropriate. Context initialisation and usage incurs no dynamic
* allocation, so there is no release function.
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
const br_hash_class *dig_vtable;
unsigned char ksi[64], kso[64];
#endif
} br_hmac_key_context;
/**
* \brief HMAC key context initialisation.
*
* Initialise the key context with the provided key, using the hash function
* identified by `digest_vtable`. This supports arbitrary key lengths.
*
* \param kc HMAC key context to initialise.
* \param digest_vtable pointer to the hash function implementation vtable.
* \param key pointer to the HMAC secret key.
* \param key_len HMAC secret key length (in bytes).
*/
void br_hmac_key_init(br_hmac_key_context *kc,
const br_hash_class *digest_vtable, const void *key, size_t key_len);
/*
* \brief Get the underlying hash function.
*
* This function returns a pointer to the implementation vtable of the
* hash function used for this HMAC key context.
*
* \param kc HMAC key context.
* \return the hash function implementation.
*/
static inline const br_hash_class *br_hmac_key_get_digest(
const br_hmac_key_context *kc)
{
return kc->dig_vtable;
}
/**
* \brief HMAC computation context.
*
* The HMAC computation context maintains the state for a single HMAC
* computation. It is modified as input bytes are injected. The context
* is caller-allocated and has no release function since it does not
* dynamically allocate external resources. Its contents are opaque.
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
br_hash_compat_context dig;
unsigned char kso[64];
size_t out_len;
#endif
} br_hmac_context;
/**
* \brief HMAC computation initialisation.
*
* Initialise a HMAC context with a key context. The key context is
* unmodified. Relevant data from the key context is immediately copied;
* the key context can thus be independently reused, modified or released
* without impacting this HMAC computation.
*
* An explicit output length can be specified; the actual output length
* will be the minimum of that value and the natural HMAC output length.
* If `out_len` is 0, then the natural HMAC output length is selected. The
* "natural output length" is the output length of the underlying hash
* function.
*
* \param ctx HMAC context to initialise.
* \param kc HMAC key context (already initialised with the key).
* \param out_len HMAC output length (0 to select "natural length").
*/
void br_hmac_init(br_hmac_context *ctx,
const br_hmac_key_context *kc, size_t out_len);
/**
* \brief Get the HMAC output size.
*
* The HMAC output size is the number of bytes that will actually be
* produced with `br_hmac_out()` with the provided context. This function
* MUST NOT be called on a non-initialised HMAC computation context.
* The returned value is the minimum of the HMAC natural length (output
* size of the underlying hash function) and the `out_len` parameter which
* was used with the last `br_hmac_init()` call on that context (if the
* initialisation `out_len` parameter was 0, then this function will
* return the HMAC natural length).
*
* \param ctx the (already initialised) HMAC computation context.
* \return the HMAC actual output size.
*/
static inline size_t
br_hmac_size(br_hmac_context *ctx)
{
return ctx->out_len;
}
/*
* \brief Get the underlying hash function.
*
* This function returns a pointer to the implementation vtable of the
* hash function used for this HMAC context.
*
* \param hc HMAC context.
* \return the hash function implementation.
*/
static inline const br_hash_class *br_hmac_get_digest(
const br_hmac_context *hc)
{
return hc->dig.vtable;
}
/**
* \brief Inject some bytes in HMAC.
*
* The provided `len` bytes are injected as extra input in the HMAC
* computation incarnated by the `ctx` HMAC context. It is acceptable
* that `len` is zero, in which case `data` is ignored (and may be
* `NULL`) and this function does nothing.
*/
void br_hmac_update(br_hmac_context *ctx, const void *data, size_t len);
/**
* \brief Compute the HMAC output.
*
* The destination buffer MUST be large enough to accommodate the result;
* its length is at most the "natural length" of HMAC (i.e. the output
* length of the underlying hash function). The context is NOT modified;
* further bytes may be processed. Thus, "partial HMAC" values can be
* efficiently obtained.
*
* Returned value is the output length (in bytes).
*
* \param ctx HMAC computation context.
* \param out destination buffer for the HMAC output.
* \return the produced value length (in bytes).
*/
size_t br_hmac_out(const br_hmac_context *ctx, void *out);
/**
* \brief Constant-time HMAC computation.
*
* This function compute the HMAC output in constant time. Some extra
* input bytes are processed, then the output is computed. The extra
* input consists in the `len` bytes pointed to by `data`. The `len`
* parameter must lie between `min_len` and `max_len` (inclusive);
* `max_len` bytes are actually read from `data`. Computing time (and
* memory access pattern) will not depend upon the data byte contents or
* the value of `len`.
*
* The output is written in the `out` buffer, that MUST be large enough
* to receive it.
*
* The difference `max_len - min_len` MUST be less than 2<sup>30</sup>
* (i.e. about one gigabyte).
*
* This function computes the output properly only if the underlying
* hash function uses MD padding (i.e. MD5, SHA-1, SHA-224, SHA-256,
* SHA-384 or SHA-512).
*
* The provided context is NOT modified.
*
* \param ctx the (already initialised) HMAC computation context.
* \param data the extra input bytes.
* \param len the extra input length (in bytes).
* \param min_len minimum extra input length (in bytes).
* \param max_len maximum extra input length (in bytes).
* \param out destination buffer for the HMAC output.
* \return the produced value length (in bytes).
*/
size_t br_hmac_outCT(const br_hmac_context *ctx,
const void *data, size_t len, size_t min_len, size_t max_len,
void *out);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,284 @@
/*
* Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
#ifndef BR_BEARSSL_KDF_H__
#define BR_BEARSSL_KDF_H__
#include <stddef.h>
#include <stdint.h>
#include "bearssl_hash.h"
#include "bearssl_hmac.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file bearssl_kdf.h
*
* # Key Derivation Functions
*
* KDF are functions that takes a variable length input, and provide a
* variable length output, meant to be used to derive subkeys from a
* master key.
*
* ## HKDF
*
* HKDF is a KDF defined by [RFC 5869](https://tools.ietf.org/html/rfc5869).
* It is based on HMAC, itself using an underlying hash function. Any
* hash function can be used, as long as it is compatible with the rules
* for the HMAC implementation (i.e. output size is 64 bytes or less, hash
* internal state size is 64 bytes or less, and the internal block length is
* a power of 2 between 16 and 256 bytes). HKDF has two phases:
*
* - HKDF-Extract: the input data in ingested, along with a "salt" value.
*
* - HKDF-Expand: the output is produced, from the result of processing
* the input and salt, and using an extra non-secret parameter called
* "info".
*
* The "salt" and "info" strings are non-secret and can be empty. Their role
* is normally to bind the input and output, respectively, to conventional
* identifiers that qualifu them within the used protocol or application.
*
* The implementation defined in this file uses the following functions:
*
* - `br_hkdf_init()`: initialize an HKDF context, with a hash function,
* and the salt. This starts the HKDF-Extract process.
*
* - `br_hkdf_inject()`: inject more input bytes. This function may be
* called repeatedly if the input data is provided by chunks.
*
* - `br_hkdf_flip()`: end the HKDF-Extract process, and start the
* HKDF-Expand process.
*
* - `br_hkdf_produce()`: get the next bytes of output. This function
* may be called several times to obtain the full output by chunks.
* For correct HKDF processing, the same "info" string must be
* provided for each call.
*
* Note that the HKDF total output size (the number of bytes that
* HKDF-Expand is willing to produce) is limited: if the hash output size
* is _n_ bytes, then the maximum output size is _255*n_.
*
* ## SHAKE
*
* SHAKE is defined in
* [FIPS 202](https://csrc.nist.gov/publications/detail/fips/202/final)
* under two versions: SHAKE128 and SHAKE256, offering an alleged
* "security level" of 128 and 256 bits, respectively (SHAKE128 is
* about 20 to 25% faster than SHAKE256). SHAKE internally relies on
* the Keccak family of sponge functions, not on any externally provided
* hash function. Contrary to HKDF, SHAKE does not have a concept of
* either a "salt" or an "info" string. The API consists in four
* functions:
*
* - `br_shake_init()`: initialize a SHAKE context for a given
* security level.
*
* - `br_shake_inject()`: inject more input bytes. This function may be
* called repeatedly if the input data is provided by chunks.
*
* - `br_shake_flip()`: end the data injection process, and start the
* data production process.
*
* - `br_shake_produce()`: get the next bytes of output. This function
* may be called several times to obtain the full output by chunks.
*/
/**
* \brief HKDF context.
*
* The HKDF context is initialized with a hash function implementation
* and a salt value. Contents are opaque (callers should not access them
* directly). The caller is responsible for allocating the context where
* appropriate. Context initialisation and usage incurs no dynamic
* allocation, so there is no release function.
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
union {
br_hmac_context hmac_ctx;
br_hmac_key_context prk_ctx;
} u;
unsigned char buf[64];
size_t ptr;
size_t dig_len;
unsigned chunk_num;
#endif
} br_hkdf_context;
/**
* \brief HKDF context initialization.
*
* The underlying hash function and salt value are provided. Arbitrary
* salt lengths can be used.
*
* HKDF makes a difference between a salt of length zero, and an
* absent salt (the latter being equivalent to a salt consisting of
* bytes of value zero, of the same length as the hash function output).
* If `salt_len` is zero, then this function assumes that the salt is
* present but of length zero. To specify an _absent_ salt, use
* `BR_HKDF_NO_SALT` as `salt` parameter (`salt_len` is then ignored).
*
* \param hc HKDF context to initialise.
* \param digest_vtable pointer to the hash function implementation vtable.
* \param salt HKDF-Extract salt.
* \param salt_len HKDF-Extract salt length (in bytes).
*/
void br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable,
const void *salt, size_t salt_len);
/**
* \brief The special "absent salt" value for HKDF.
*/
#define BR_HKDF_NO_SALT (&br_hkdf_no_salt)
#ifndef BR_DOXYGEN_IGNORE
extern const unsigned char br_hkdf_no_salt;
#endif
/**
* \brief HKDF input injection (HKDF-Extract).
*
* This function injects some more input bytes ("key material") into
* HKDF. This function may be called several times, after `br_hkdf_init()`
* but before `br_hkdf_flip()`.
*
* \param hc HKDF context.
* \param ikm extra input bytes.
* \param ikm_len number of extra input bytes.
*/
void br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len);
/**
* \brief HKDF switch to the HKDF-Expand phase.
*
* This call terminates the HKDF-Extract process (input injection), and
* starts the HKDF-Expand process (output production).
*
* \param hc HKDF context.
*/
void br_hkdf_flip(br_hkdf_context *hc);
/**
* \brief HKDF output production (HKDF-Expand).
*
* Produce more output bytes from the current state. This function may be
* called several times, but only after `br_hkdf_flip()`.
*
* Returned value is the number of actually produced bytes. The total
* output length is limited to 255 times the output length of the
* underlying hash function.
*
* \param hc HKDF context.
* \param info application specific information string.
* \param info_len application specific information string length (in bytes).
* \param out destination buffer for the HKDF output.
* \param out_len the length of the requested output (in bytes).
* \return the produced output length (in bytes).
*/
size_t br_hkdf_produce(br_hkdf_context *hc,
const void *info, size_t info_len, void *out, size_t out_len);
/**
* \brief SHAKE context.
*
* The HKDF context is initialized with a "security level". The internal
* notion is called "capacity"; the capacity is twice the security level
* (for instance, SHAKE128 has capacity 256).
*
* The caller is responsible for allocating the context where
* appropriate. Context initialisation and usage incurs no dynamic
* allocation, so there is no release function.
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
unsigned char dbuf[200];
size_t dptr;
size_t rate;
uint64_t A[25];
#endif
} br_shake_context;
/**
* \brief SHAKE context initialization.
*
* The context is initialized for the provided "security level".
* Internally, this sets the "capacity" to twice the security level;
* thus, for SHAKE128, the `security_level` parameter should be 128,
* which corresponds to a 256-bit capacity.
*
* Allowed security levels are all multiples of 32, from 32 to 768,
* inclusive. Larger security levels imply lower performance; levels
* beyond 256 bits don't make much sense. Standard levels are 128
* and 256 bits (for SHAKE128 and SHAKE256, respectively).
*
* \param sc SHAKE context to initialise.
* \param security_level security level (in bits).
*/
void br_shake_init(br_shake_context *sc, int security_level);
/**
* \brief SHAKE input injection.
*
* This function injects some more input bytes ("key material") into
* SHAKE. This function may be called several times, after `br_shake_init()`
* but before `br_shake_flip()`.
*
* \param sc SHAKE context.
* \param data extra input bytes.
* \param len number of extra input bytes.
*/
void br_shake_inject(br_shake_context *sc, const void *data, size_t len);
/**
* \brief SHAKE switch to production phase.
*
* This call terminates the input injection process, and starts the
* output production process.
*
* \param sc SHAKE context.
*/
void br_shake_flip(br_shake_context *hc);
/**
* \brief SHAKE output production.
*
* Produce more output bytes from the current state. This function may be
* called several times, but only after `br_shake_flip()`.
*
* There is no practical limit to the number of bytes that may be produced.
*
* \param sc SHAKE context.
* \param out destination buffer for the SHAKE output.
* \param len the length of the requested output (in bytes).
*/
void br_shake_produce(br_shake_context *sc, void *out, size_t len);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,294 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
#ifndef BR_BEARSSL_PEM_H__
#define BR_BEARSSL_PEM_H__
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \file bearssl_pem.h
*
* # PEM Support
*
* PEM is a traditional encoding layer use to store binary objects (in
* particular X.509 certificates, and private keys) in text files. While
* the acronym comes from an old, defunct standard ("Privacy Enhanced
* Mail"), the format has been reused, with some variations, by many
* systems, and is a _de facto_ standard, even though it is not, actually,
* specified in all clarity anywhere.
*
* ## Format Details
*
* BearSSL contains a generic, streamed PEM decoder, which handles the
* following format:
*
* - The input source (a sequence of bytes) is assumed to be the
* encoding of a text file in an ASCII-compatible charset. This
* includes ISO-8859-1, Windows-1252, and UTF-8 encodings. Each
* line ends on a newline character (U+000A LINE FEED). The
* U+000D CARRIAGE RETURN characters are ignored, so the code
* accepts both Windows-style and Unix-style line endings.
*
* - Each object begins with a banner that occurs at the start of
* a line; the first banner characters are "`-----BEGIN `" (five
* dashes, the word "BEGIN", and a space). The banner matching is
* not case-sensitive.
*
* - The _object name_ consists in the characters that follow the
* banner start sequence, up to the end of the line, but without
* trailing dashes (in "normal" PEM, there are five trailing
* dashes, but this implementation is not picky about these dashes).
* The BearSSL decoder normalises the name characters to uppercase
* (for ASCII letters only) and accepts names up to 127 characters.
*
* - The object ends with a banner that again occurs at the start of
* a line, and starts with "`-----END `" (again case-insensitive).
*
* - Between that start and end banner, only Base64 data shall occur.
* Base64 converts each sequence of three bytes into four
* characters; the four characters are ASCII letters, digits, "`+`"
* or "`-`" signs, and one or two "`=`" signs may occur in the last
* quartet. Whitespace is ignored (whitespace is any ASCII character
* of code 32 or less, so control characters are whitespace) and
* lines may have arbitrary length; the only restriction is that the
* four characters of a quartet must appear on the same line (no
* line break inside a quartet).
*
* - A single file may contain more than one PEM object. Bytes that
* occur between objects are ignored.
*
*
* ## PEM Decoder API
*
* The PEM decoder offers a state-machine API. The caller allocates a
* decoder context, then injects source bytes. Source bytes are pushed
* with `br_pem_decoder_push()`. The decoder stops accepting bytes when
* it reaches an "event", which is either the start of an object, the
* end of an object, or a decoding error within an object.
*
* The `br_pem_decoder_event()` function is used to obtain the current
* event; it also clears it, thus allowing the decoder to accept more
* bytes. When a object start event is raised, the decoder context
* offers the found object name (normalised to ASCII uppercase).
*
* When an object is reached, the caller must set an appropriate callback
* function, which will receive (by chunks) the decoded object data.
*
* Since the decoder context makes no dynamic allocation, it requires
* no explicit deallocation.
*/
/**
* \brief PEM decoder context.
*
* Contents are opaque (they should not be accessed directly).
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
/* CPU for the T0 virtual machine. */
struct {
uint32_t *dp;
uint32_t *rp;
const unsigned char *ip;
} cpu;
uint32_t dp_stack[32];
uint32_t rp_stack[32];
int err;
const unsigned char *hbuf;
size_t hlen;
void (*dest)(void *dest_ctx, const void *src, size_t len);
void *dest_ctx;
unsigned char event;
char name[128];
unsigned char buf[255];
size_t ptr;
#endif
} br_pem_decoder_context;
/**
* \brief Initialise a PEM decoder structure.
*
* \param ctx decoder context to initialise.
*/
void br_pem_decoder_init(br_pem_decoder_context *ctx);
/**
* \brief Push some bytes into the decoder.
*
* Returned value is the number of bytes actually consumed; this may be
* less than the number of provided bytes if an event is raised. When an
* event is raised, it must be read (with `br_pem_decoder_event()`);
* until the event is read, this function will return 0.
*
* \param ctx decoder context.
* \param data new data bytes.
* \param len number of new data bytes.
* \return the number of bytes actually received (may be less than `len`).
*/
size_t br_pem_decoder_push(br_pem_decoder_context *ctx,
const void *data, size_t len);
/**
* \brief Set the receiver for decoded data.
*
* When an object is entered, the provided function (with opaque context
* pointer) will be called repeatedly with successive chunks of decoded
* data for that object. If `dest` is set to 0, then decoded data is
* simply ignored. The receiver can be set at any time, but, in practice,
* it should be called immediately after receiving a "start of object"
* event.
*
* \param ctx decoder context.
* \param dest callback for receiving decoded data.
* \param dest_ctx opaque context pointer for the `dest` callback.
*/
static inline void
br_pem_decoder_setdest(br_pem_decoder_context *ctx,
void (*dest)(void *dest_ctx, const void *src, size_t len),
void *dest_ctx)
{
ctx->dest = dest;
ctx->dest_ctx = dest_ctx;
}
/**
* \brief Get the last event.
*
* If an event was raised, then this function returns the event value, and
* also clears it, thereby allowing the decoder to proceed. If no event
* was raised since the last call to `br_pem_decoder_event()`, then this
* function returns 0.
*
* \param ctx decoder context.
* \return the raised event, or 0.
*/
int br_pem_decoder_event(br_pem_decoder_context *ctx);
/**
* \brief Event: start of object.
*
* This event is raised when the start of a new object has been detected.
* The object name (normalised to uppercase) can be accessed with
* `br_pem_decoder_name()`.
*/
#define BR_PEM_BEGIN_OBJ 1
/**
* \brief Event: end of object.
*
* This event is raised when the end of the current object is reached
* (normally, i.e. with no decoding error).
*/
#define BR_PEM_END_OBJ 2
/**
* \brief Event: decoding error.
*
* This event is raised when decoding fails within an object.
* This formally closes the current object and brings the decoder back
* to the "out of any object" state. The offending line in the source
* is consumed.
*/
#define BR_PEM_ERROR 3
/**
* \brief Get the name of the encountered object.
*
* The encountered object name is defined only when the "start of object"
* event is raised. That name is normalised to uppercase (for ASCII letters
* only) and does not include trailing dashes.
*
* \param ctx decoder context.
* \return the current object name.
*/
static inline const char *
br_pem_decoder_name(br_pem_decoder_context *ctx)
{
return ctx->name;
}
/**
* \brief Encode an object in PEM.
*
* This function encodes the provided binary object (`data`, of length `len`
* bytes) into PEM. The `banner` text will be included in the header and
* footer (e.g. use `"CERTIFICATE"` to get a `"BEGIN CERTIFICATE"` header).
*
* The length (in characters) of the PEM output is returned; that length
* does NOT include the terminating zero, that this function nevertheless
* adds. If using the returned value for allocation purposes, the allocated
* buffer size MUST be at least one byte larger than the returned size.
*
* If `dest` is `NULL`, then the encoding does not happen; however, the
* length of the encoded object is still computed and returned.
*
* The `data` pointer may be `NULL` only if `len` is zero (when encoding
* an object of length zero, which is not very useful), or when `dest`
* is `NULL` (in that case, source data bytes are ignored).
*
* Some `flags` can be specified to alter the encoding behaviour:
*
* - If `BR_PEM_LINE64` is set, then line-breaking will occur after
* every 64 characters of output, instead of the default of 76.
*
* - If `BR_PEM_CRLF` is set, then end-of-line sequence will use
* CR+LF instead of a single LF.
*
* The `data` and `dest` buffers may overlap, in which case the source
* binary data is destroyed in the process. Note that the PEM-encoded output
* is always larger than the source binary.
*
* \param dest the destination buffer (or `NULL`).
* \param data the source buffer (can be `NULL` in some cases).
* \param len the source length (in bytes).
* \param banner the PEM banner expression.
* \param flags the behavioural flags.
* \return the PEM object length (in characters), EXCLUDING the final zero.
*/
size_t br_pem_encode(void *dest, const void *data, size_t len,
const char *banner, unsigned flags);
/**
* \brief PEM encoding flag: split lines at 64 characters.
*/
#define BR_PEM_LINE64 0x0001
/**
* \brief PEM encoding flag: use CR+LF line endings.
*/
#define BR_PEM_CRLF 0x0002
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,150 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
#ifndef BR_BEARSSL_PRF_H__
#define BR_BEARSSL_PRF_H__
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \file bearssl_prf.h
*
* # The TLS PRF
*
* The "PRF" is the pseudorandom function used internally during the
* SSL/TLS handshake, notably to expand negotiated shared secrets into
* the symmetric encryption keys that will be used to process the
* application data.
*
* TLS 1.0 and 1.1 define a PRF that is based on both MD5 and SHA-1. This
* is implemented by the `br_tls10_prf()` function.
*
* TLS 1.2 redefines the PRF, using an explicit hash function. The
* `br_tls12_sha256_prf()` and `br_tls12_sha384_prf()` functions apply that
* PRF with, respectively, SHA-256 and SHA-384. Most standard cipher suites
* rely on the SHA-256 based PRF, but some use SHA-384.
*
* The PRF always uses as input three parameters: a "secret" (some
* bytes), a "label" (ASCII string), and a "seed" (again some bytes). An
* arbitrary output length can be produced. The "seed" is provided as an
* arbitrary number of binary chunks, that gets internally concatenated.
*/
/**
* \brief Type for a seed chunk.
*
* Each chunk may have an arbitrary length, and may be empty (no byte at
* all). If the chunk length is zero, then the pointer to the chunk data
* may be `NULL`.
*/
typedef struct {
/**
* \brief Pointer to the chunk data.
*/
const void *data;
/**
* \brief Chunk length (in bytes).
*/
size_t len;
} br_tls_prf_seed_chunk;
/**
* \brief PRF implementation for TLS 1.0 and 1.1.
*
* This PRF is the one specified by TLS 1.0 and 1.1. It internally uses
* MD5 and SHA-1.
*
* \param dst destination buffer.
* \param len output length (in bytes).
* \param secret secret value (key) for this computation.
* \param secret_len length of "secret" (in bytes).
* \param label PRF label (zero-terminated ASCII string).
* \param seed_num number of seed chunks.
* \param seed seed chnks for this computation (usually non-secret).
*/
void br_tls10_prf(void *dst, size_t len,
const void *secret, size_t secret_len, const char *label,
size_t seed_num, const br_tls_prf_seed_chunk *seed);
/**
* \brief PRF implementation for TLS 1.2, with SHA-256.
*
* This PRF is the one specified by TLS 1.2, when the underlying hash
* function is SHA-256.
*
* \param dst destination buffer.
* \param len output length (in bytes).
* \param secret secret value (key) for this computation.
* \param secret_len length of "secret" (in bytes).
* \param label PRF label (zero-terminated ASCII string).
* \param seed_num number of seed chunks.
* \param seed seed chnks for this computation (usually non-secret).
*/
void br_tls12_sha256_prf(void *dst, size_t len,
const void *secret, size_t secret_len, const char *label,
size_t seed_num, const br_tls_prf_seed_chunk *seed);
/**
* \brief PRF implementation for TLS 1.2, with SHA-384.
*
* This PRF is the one specified by TLS 1.2, when the underlying hash
* function is SHA-384.
*
* \param dst destination buffer.
* \param len output length (in bytes).
* \param secret secret value (key) for this computation.
* \param secret_len length of "secret" (in bytes).
* \param label PRF label (zero-terminated ASCII string).
* \param seed_num number of seed chunks.
* \param seed seed chnks for this computation (usually non-secret).
*/
void br_tls12_sha384_prf(void *dst, size_t len,
const void *secret, size_t secret_len, const char *label,
size_t seed_num, const br_tls_prf_seed_chunk *seed);
/**
* brief A convenient type name for a PRF implementation.
*
* \param dst destination buffer.
* \param len output length (in bytes).
* \param secret secret value (key) for this computation.
* \param secret_len length of "secret" (in bytes).
* \param label PRF label (zero-terminated ASCII string).
* \param seed_num number of seed chunks.
* \param seed seed chnks for this computation (usually non-secret).
*/
typedef void (*br_tls_prf_impl)(void *dst, size_t len,
const void *secret, size_t secret_len, const char *label,
size_t seed_num, const br_tls_prf_seed_chunk *seed);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,397 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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.
*/
#ifndef BR_BEARSSL_RAND_H__
#define BR_BEARSSL_RAND_H__
#include <stddef.h>
#include <stdint.h>
#include "bearssl_block.h"
#include "bearssl_hash.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file bearssl_rand.h
*
* # Pseudo-Random Generators
*
* A PRNG is a state-based engine that outputs pseudo-random bytes on
* demand. It is initialized with an initial seed, and additional seed
* bytes can be added afterwards. Bytes produced depend on the seeds and
* also on the exact sequence of calls (including sizes requested for
* each call).
*
*
* ## Procedural and OOP API
*
* For the PRNG of name "`xxx`", two API are provided. The _procedural_
* API defined a context structure `br_xxx_context` and three functions:
*
* - `br_xxx_init()`
*
* Initialise the context with an initial seed.
*
* - `br_xxx_generate()`
*
* Produce some pseudo-random bytes.
*
* - `br_xxx_update()`
*
* Inject some additional seed.
*
* The initialisation function sets the first context field (`vtable`)
* to a pointer to the vtable that supports the OOP API. The OOP API
* provides access to the same functions through function pointers,
* named `init()`, `generate()` and `update()`.
*
* Note that the context initialisation method may accept additional
* parameters, provided as a 'const void *' pointer at API level. These
* additional parameters depend on the implemented PRNG.
*
*
* ## HMAC_DRBG
*
* HMAC_DRBG is defined in [NIST SP 800-90A Revision
* 1](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf).
* It uses HMAC repeatedly, over some configurable underlying hash
* function. In BearSSL, it is implemented under the "`hmac_drbg`" name.
* The "extra parameters" pointer for context initialisation should be
* set to a pointer to the vtable for the underlying hash function (e.g.
* pointer to `br_sha256_vtable` to use HMAC_DRBG with SHA-256).
*
* According to the NIST standard, each request shall produce up to
* 2<sup>19</sup> bits (i.e. 64 kB of data); moreover, the context shall
* be reseeded at least once every 2<sup>48</sup> requests. This
* implementation does not maintain the reseed counter (the threshold is
* too high to be reached in practice) and does not object to producing
* more than 64 kB in a single request; thus, the code cannot fail,
* which corresponds to the fact that the API has no room for error
* codes. However, this implies that requesting more than 64 kB in one
* `generate()` request, or making more than 2<sup>48</sup> requests
* without reseeding, is formally out of NIST specification. There is
* no currently known security penalty for exceeding the NIST limits,
* and, in any case, HMAC_DRBG usage in implementing SSL/TLS always
* stays much below these thresholds.
*
*
* ## AESCTR_DRBG
*
* AESCTR_DRBG is a custom PRNG based on AES-128 in CTR mode. This is
* meant to be used only in situations where you are desperate for
* speed, and have an hardware-optimized AES/CTR implementation. Whether
* this will yield perceptible improvements depends on what you use the
* pseudorandom bytes for, and how many you want; for instance, RSA key
* pair generation uses a substantial amount of randomness, and using
* AESCTR_DRBG instead of HMAC_DRBG yields a 15 to 20% increase in key
* generation speed on a recent x86 CPU (Intel Core i7-6567U at 3.30 GHz).
*
* Internally, it uses CTR mode with successive counter values, starting
* at zero (counter value expressed over 128 bits, big-endian convention).
* The counter is not allowed to reach 32768; thus, every 32768*16 bytes
* at most, the `update()` function is run (on an empty seed, if none is
* provided). The `update()` function computes the new AES-128 key by
* applying a custom hash function to the concatenation of a state-dependent
* word (encryption of an all-one block with the current key) and the new
* seed. The custom hash function uses Hirose's construction over AES-256;
* see the comments in `aesctr_drbg.c` for details.
*
* This DRBG does not follow an existing standard, and thus should be
* considered as inadequate for production use until it has been properly
* analysed.
*/
/**
* \brief Class type for PRNG implementations.
*
* A `br_prng_class` instance references the methods implementing a PRNG.
* Constant instances of this structure are defined for each implemented
* PRNG. Such instances are also called "vtables".
*/
typedef struct br_prng_class_ br_prng_class;
struct br_prng_class_ {
/**
* \brief Size (in bytes) of the context structure appropriate for
* running this PRNG.
*/
size_t context_size;
/**
* \brief Initialisation method.
*
* The context to initialise is provided as a pointer to its
* first field (the vtable pointer); this function sets that
* first field to a pointer to the vtable.
*
* The extra parameters depend on the implementation; each
* implementation defines what kind of extra parameters it
* expects (if any).
*
* Requirements on the initial seed depend on the implemented
* PRNG.
*
* \param ctx PRNG context to initialise.
* \param params extra parameters for the PRNG.
* \param seed initial seed.
* \param seed_len initial seed length (in bytes).
*/
void (*init)(const br_prng_class **ctx, const void *params,
const void *seed, size_t seed_len);
/**
* \brief Random bytes generation.
*
* This method produces `len` pseudorandom bytes, in the `out`
* buffer. The context is updated accordingly.
*
* \param ctx PRNG context.
* \param out output buffer.
* \param len number of pseudorandom bytes to produce.
*/
void (*generate)(const br_prng_class **ctx, void *out, size_t len);
/**
* \brief Inject additional seed bytes.
*
* The provided seed bytes are added into the PRNG internal
* entropy pool.
*
* \param ctx PRNG context.
* \param seed additional seed.
* \param seed_len additional seed length (in bytes).
*/
void (*update)(const br_prng_class **ctx,
const void *seed, size_t seed_len);
};
/**
* \brief Context for HMAC_DRBG.
*
* The context contents are opaque, except the first field, which
* supports OOP.
*/
typedef struct {
/**
* \brief Pointer to the vtable.
*
* This field is set with the initialisation method/function.
*/
const br_prng_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
unsigned char K[64];
unsigned char V[64];
const br_hash_class *digest_class;
#endif
} br_hmac_drbg_context;
/**
* \brief Statically allocated, constant vtable for HMAC_DRBG.
*/
extern const br_prng_class br_hmac_drbg_vtable;
/**
* \brief HMAC_DRBG initialisation.
*
* The context to initialise is provided as a pointer to its first field
* (the vtable pointer); this function sets that first field to a
* pointer to the vtable.
*
* The `seed` value is what is called, in NIST terminology, the
* concatenation of the "seed", "nonce" and "personalization string", in
* that order.
*
* The `digest_class` parameter defines the underlying hash function.
* Formally, the NIST standard specifies that the hash function shall
* be only SHA-1 or one of the SHA-2 functions. This implementation also
* works with any other implemented hash function (such as MD5), but
* this is non-standard and therefore not recommended.
*
* \param ctx HMAC_DRBG context to initialise.
* \param digest_class vtable for the underlying hash function.
* \param seed initial seed.
* \param seed_len initial seed length (in bytes).
*/
void br_hmac_drbg_init(br_hmac_drbg_context *ctx,
const br_hash_class *digest_class, const void *seed, size_t seed_len);
/**
* \brief Random bytes generation with HMAC_DRBG.
*
* This method produces `len` pseudorandom bytes, in the `out`
* buffer. The context is updated accordingly. Formally, requesting
* more than 65536 bytes in one request falls out of specification
* limits (but it won't fail).
*
* \param ctx HMAC_DRBG context.
* \param out output buffer.
* \param len number of pseudorandom bytes to produce.
*/
void br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len);
/**
* \brief Inject additional seed bytes in HMAC_DRBG.
*
* The provided seed bytes are added into the HMAC_DRBG internal
* entropy pool. The process does not _replace_ existing entropy,
* thus pushing non-random bytes (i.e. bytes which are known to the
* attackers) does not degrade the overall quality of generated bytes.
*
* \param ctx HMAC_DRBG context.
* \param seed additional seed.
* \param seed_len additional seed length (in bytes).
*/
void br_hmac_drbg_update(br_hmac_drbg_context *ctx,
const void *seed, size_t seed_len);
/**
* \brief Get the hash function implementation used by a given instance of
* HMAC_DRBG.
*
* This calls MUST NOT be performed on a context which was not
* previously initialised.
*
* \param ctx HMAC_DRBG context.
* \return the hash function vtable.
*/
static inline const br_hash_class *
br_hmac_drbg_get_hash(const br_hmac_drbg_context *ctx)
{
return ctx->digest_class;
}
/**
* \brief Type for a provider of entropy seeds.
*
* A "seeder" is a function that is able to obtain random values from
* some source and inject them as entropy seed in a PRNG. A seeder
* shall guarantee that the total entropy of the injected seed is large
* enough to seed a PRNG for purposes of cryptographic key generation
* (i.e. at least 128 bits).
*
* A seeder may report a failure to obtain adequate entropy. Seeders
* shall endeavour to fix themselves transient errors by trying again;
* thus, callers may consider reported errors as permanent.
*
* \param ctx PRNG context to seed.
* \return 1 on success, 0 on error.
*/
typedef int (*br_prng_seeder)(const br_prng_class **ctx);
/**
* \brief Get a seeder backed by the operating system or hardware.
*
* Get a seeder that feeds on RNG facilities provided by the current
* operating system or hardware. If no such facility is known, then 0
* is returned.
*
* If `name` is not `NULL`, then `*name` is set to a symbolic string
* that identifies the seeder implementation. If no seeder is returned
* and `name` is not `NULL`, then `*name` is set to a pointer to the
* constant string `"none"`.
*
* \param name receiver for seeder name, or `NULL`.
* \return the system seeder, if available, or 0.
*/
br_prng_seeder br_prng_seeder_system(const char **name);
/**
* \brief Context for AESCTR_DRBG.
*
* The context contents are opaque, except the first field, which
* supports OOP.
*/
typedef struct {
/**
* \brief Pointer to the vtable.
*
* This field is set with the initialisation method/function.
*/
const br_prng_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
br_aes_gen_ctr_keys sk;
uint32_t cc;
#endif
} br_aesctr_drbg_context;
/**
* \brief Statically allocated, constant vtable for AESCTR_DRBG.
*/
extern const br_prng_class br_aesctr_drbg_vtable;
/**
* \brief AESCTR_DRBG initialisation.
*
* The context to initialise is provided as a pointer to its first field
* (the vtable pointer); this function sets that first field to a
* pointer to the vtable.
*
* The internal AES key is first set to the all-zero key; then, the
* `br_aesctr_drbg_update()` function is called with the provided `seed`.
* The call is performed even if the seed length (`seed_len`) is zero.
*
* The `aesctr` parameter defines the underlying AES/CTR implementation.
*
* \param ctx AESCTR_DRBG context to initialise.
* \param aesctr vtable for the AES/CTR implementation.
* \param seed initial seed (can be `NULL` if `seed_len` is zero).
* \param seed_len initial seed length (in bytes).
*/
void br_aesctr_drbg_init(br_aesctr_drbg_context *ctx,
const br_block_ctr_class *aesctr, const void *seed, size_t seed_len);
/**
* \brief Random bytes generation with AESCTR_DRBG.
*
* This method produces `len` pseudorandom bytes, in the `out`
* buffer. The context is updated accordingly.
*
* \param ctx AESCTR_DRBG context.
* \param out output buffer.
* \param len number of pseudorandom bytes to produce.
*/
void br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx,
void *out, size_t len);
/**
* \brief Inject additional seed bytes in AESCTR_DRBG.
*
* The provided seed bytes are added into the AESCTR_DRBG internal
* entropy pool. The process does not _replace_ existing entropy,
* thus pushing non-random bytes (i.e. bytes which are known to the
* attackers) does not degrade the overall quality of generated bytes.
*
* \param ctx AESCTR_DRBG context.
* \param seed additional seed.
* \param seed_len additional seed length (in bytes).
*/
void br_aesctr_drbg_update(br_aesctr_drbg_context *ctx,
const void *seed, size_t seed_len);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
#
# 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.
# ======================================================================
# This file sets variables with generic default values, which can be
# overridden in the selected configuration file.
BUILD = build
OBJDIR = $(BUILD)$Pobj
BEARSSLLIB = $(BUILD)$P$(LP)bearssl$L
BEARSSLDLL = $(BUILD)$P$(DP)bearssl$D
BRSSL = $(BUILD)$Pbrssl$E
TESTCRYPTO = $(BUILD)$Ptestcrypto$E
TESTSPEED = $(BUILD)$Ptestspeed$E
TESTX509 = $(BUILD)$Ptestx509$E
INCFLAGS = -Isrc -Iinc
T0COMP = T0Comp.exe
STATICLIB = lib
DLL = dll
TOOLS = tools
TESTS = tests

View File

@ -0,0 +1,38 @@
# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
#
# 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.
# ======================================================================
# This file sets variables for use with NMake.exe, as distributed with
# Visual Studio.
# Load generic defaults.
!include mk/Defaults.mk
# Default configuration is 'Win' (native build with Visual Studio).
CONF = Win
# Path separator.
P = ^\
!include conf/$(CONF).mk
!include mk/Rules.mk

1318
contrib/bearssl/mk/Rules.mk Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
#
# 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.
# ======================================================================
# This file sets variables for use with a SingleUnix-compatible 'make'
# utility.
# Load generic default.
include mk/Defaults.mk
# Path separator.
P = /
# Default configuration is 'Unix' (native build on a Unix-like system).
CONF = Unix
include conf/$(CONF).mk
include mk/Rules.mk

View File

@ -0,0 +1,32 @@
@echo off
rem =====================================================================
rem This script uses the command-line C# compiler csc.exe, which is
rem provided with the .NET framework. We need framework 3.5 or later
rem (some of the code uses features not available in the language version
rem implemented in the compiler provided with framework 2.0.50727).
rem =====================================================================
if exist "%SystemRoot%\Microsoft.NET\Framework\v3.5\csc.exe" (
set CSC="%SystemRoot%\Microsoft.NET\Framework\v3.5\csc.exe"
goto do_compile
)
if exist "%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\csc.exe" (
set CSC="%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\csc.exe"
goto do_compile
)
if exist "%SystemRoot%\Microsoft.NET\Framework64\v3.5\csc.exe" (
set CSC="%SystemRoot%\Microsoft.NET\Framework64\v3.5\csc.exe"
goto do_compile
)
if exist "%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\csc.exe" (
set CSC="%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
goto do_compile
)
echo C# compiler not found
exit 1
:do_compile
%CSC% /nologo /out:T0Comp.exe /main:T0Comp /res:T0\kern.t0,t0-kernel T0\*.cs
if %errorlevel% neq 0 exit /b %errorlevel%

11
contrib/bearssl/mk/mkT0.sh Executable file
View File

@ -0,0 +1,11 @@
#! /bin/sh
CSC=$(which mono-csc || which dmcs || echo "none")
if [ $CSC = "none" ]; then
echo "Error: Please install mono-devel."
exit 1
fi
set -e
$CSC /out:T0Comp.exe /main:T0Comp /res:T0/kern.t0,t0-kernel T0/*.cs

570
contrib/bearssl/mk/mkrules.sh Executable file
View File

@ -0,0 +1,570 @@
#! /bin/sh
# ========================================================================
#
# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
#
# 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.
#
# ========================================================================
#
# This script is used to generate the 'Rules.mk' file from the list
# of source file included below. If the list changes (e.g. to add a
# new source file), then add it here and rerun this script.
#
# ========================================================================
# Solaris compatibility: switch to a more POSIX-compliant /bin/sh.
if [ -z "$BR_SCRIPT_LOOP" ] ; then
BR_SCRIPT_LOOP=yes
export BR_SCRIPT_LOOP
if [ -x /usr/xpg6/bin/sh ] ; then
exec /usr/xpg6/bin/sh "$0" "$@"
fi
if [ -x /usr/xpg4/bin/sh ] ; then
exec /usr/xpg4/bin/sh "$0" "$@"
fi
fi
# Exit on first error.
set -e
# Source files. Please keep in alphabetical order.
coresrc=" \
src/settings.c \
src/aead/ccm.c \
src/aead/eax.c \
src/aead/gcm.c \
src/codec/ccopy.c \
src/codec/dec16be.c \
src/codec/dec16le.c \
src/codec/dec32be.c \
src/codec/dec32le.c \
src/codec/dec64be.c \
src/codec/dec64le.c \
src/codec/enc16be.c \
src/codec/enc16le.c \
src/codec/enc32be.c \
src/codec/enc32le.c \
src/codec/enc64be.c \
src/codec/enc64le.c \
src/codec/pemdec.c \
src/codec/pemenc.c \
src/ec/ec_all_m15.c \
src/ec/ec_all_m31.c \
src/ec/ec_c25519_i15.c \
src/ec/ec_c25519_i31.c \
src/ec/ec_c25519_m15.c \
src/ec/ec_c25519_m31.c \
src/ec/ec_c25519_m62.c \
src/ec/ec_c25519_m64.c \
src/ec/ec_curve25519.c \
src/ec/ec_default.c \
src/ec/ec_keygen.c \
src/ec/ec_p256_m15.c \
src/ec/ec_p256_m31.c \
src/ec/ec_p256_m62.c \
src/ec/ec_p256_m64.c \
src/ec/ec_prime_i15.c \
src/ec/ec_prime_i31.c \
src/ec/ec_pubkey.c \
src/ec/ec_secp256r1.c \
src/ec/ec_secp384r1.c \
src/ec/ec_secp521r1.c \
src/ec/ecdsa_atr.c \
src/ec/ecdsa_default_sign_asn1.c \
src/ec/ecdsa_default_sign_raw.c \
src/ec/ecdsa_default_vrfy_asn1.c \
src/ec/ecdsa_default_vrfy_raw.c \
src/ec/ecdsa_i15_bits.c \
src/ec/ecdsa_i15_sign_asn1.c \
src/ec/ecdsa_i15_sign_raw.c \
src/ec/ecdsa_i15_vrfy_asn1.c \
src/ec/ecdsa_i15_vrfy_raw.c \
src/ec/ecdsa_i31_bits.c \
src/ec/ecdsa_i31_sign_asn1.c \
src/ec/ecdsa_i31_sign_raw.c \
src/ec/ecdsa_i31_vrfy_asn1.c \
src/ec/ecdsa_i31_vrfy_raw.c \
src/ec/ecdsa_rta.c \
src/hash/dig_oid.c \
src/hash/dig_size.c \
src/hash/ghash_ctmul.c \
src/hash/ghash_ctmul32.c \
src/hash/ghash_ctmul64.c \
src/hash/ghash_pclmul.c \
src/hash/ghash_pwr8.c \
src/hash/md5.c \
src/hash/md5sha1.c \
src/hash/mgf1.c \
src/hash/multihash.c \
src/hash/sha1.c \
src/hash/sha2big.c \
src/hash/sha2small.c \
src/int/i15_add.c \
src/int/i15_bitlen.c \
src/int/i15_decmod.c \
src/int/i15_decode.c \
src/int/i15_decred.c \
src/int/i15_encode.c \
src/int/i15_fmont.c \
src/int/i15_iszero.c \
src/int/i15_moddiv.c \
src/int/i15_modpow.c \
src/int/i15_modpow2.c \
src/int/i15_montmul.c \
src/int/i15_mulacc.c \
src/int/i15_muladd.c \
src/int/i15_ninv15.c \
src/int/i15_reduce.c \
src/int/i15_rshift.c \
src/int/i15_sub.c \
src/int/i15_tmont.c \
src/int/i31_add.c \
src/int/i31_bitlen.c \
src/int/i31_decmod.c \
src/int/i31_decode.c \
src/int/i31_decred.c \
src/int/i31_encode.c \
src/int/i31_fmont.c \
src/int/i31_iszero.c \
src/int/i31_moddiv.c \
src/int/i31_modpow.c \
src/int/i31_modpow2.c \
src/int/i31_montmul.c \
src/int/i31_mulacc.c \
src/int/i31_muladd.c \
src/int/i31_ninv31.c \
src/int/i31_reduce.c \
src/int/i31_rshift.c \
src/int/i31_sub.c \
src/int/i31_tmont.c \
src/int/i32_add.c \
src/int/i32_bitlen.c \
src/int/i32_decmod.c \
src/int/i32_decode.c \
src/int/i32_decred.c \
src/int/i32_div32.c \
src/int/i32_encode.c \
src/int/i32_fmont.c \
src/int/i32_iszero.c \
src/int/i32_modpow.c \
src/int/i32_montmul.c \
src/int/i32_mulacc.c \
src/int/i32_muladd.c \
src/int/i32_ninv32.c \
src/int/i32_reduce.c \
src/int/i32_sub.c \
src/int/i32_tmont.c \
src/int/i62_modpow2.c \
src/kdf/hkdf.c \
src/kdf/shake.c \
src/mac/hmac.c \
src/mac/hmac_ct.c \
src/rand/aesctr_drbg.c \
src/rand/hmac_drbg.c \
src/rand/sysrng.c \
src/rsa/rsa_default_keygen.c \
src/rsa/rsa_default_modulus.c \
src/rsa/rsa_default_oaep_decrypt.c \
src/rsa/rsa_default_oaep_encrypt.c \
src/rsa/rsa_default_pkcs1_sign.c \
src/rsa/rsa_default_pkcs1_vrfy.c \
src/rsa/rsa_default_priv.c \
src/rsa/rsa_default_privexp.c \
src/rsa/rsa_default_pss_sign.c \
src/rsa/rsa_default_pss_vrfy.c \
src/rsa/rsa_default_pub.c \
src/rsa/rsa_default_pubexp.c \
src/rsa/rsa_i15_keygen.c \
src/rsa/rsa_i15_modulus.c \
src/rsa/rsa_i15_oaep_decrypt.c \
src/rsa/rsa_i15_oaep_encrypt.c \
src/rsa/rsa_i15_pkcs1_sign.c \
src/rsa/rsa_i15_pkcs1_vrfy.c \
src/rsa/rsa_i15_priv.c \
src/rsa/rsa_i15_privexp.c \
src/rsa/rsa_i15_pss_sign.c \
src/rsa/rsa_i15_pss_vrfy.c \
src/rsa/rsa_i15_pub.c \
src/rsa/rsa_i15_pubexp.c \
src/rsa/rsa_i31_keygen.c \
src/rsa/rsa_i31_keygen_inner.c \
src/rsa/rsa_i31_modulus.c \
src/rsa/rsa_i31_oaep_decrypt.c \
src/rsa/rsa_i31_oaep_encrypt.c \
src/rsa/rsa_i31_pkcs1_sign.c \
src/rsa/rsa_i31_pkcs1_vrfy.c \
src/rsa/rsa_i31_priv.c \
src/rsa/rsa_i31_privexp.c \
src/rsa/rsa_i31_pss_sign.c \
src/rsa/rsa_i31_pss_vrfy.c \
src/rsa/rsa_i31_pub.c \
src/rsa/rsa_i31_pubexp.c \
src/rsa/rsa_i32_oaep_decrypt.c \
src/rsa/rsa_i32_oaep_encrypt.c \
src/rsa/rsa_i32_pkcs1_sign.c \
src/rsa/rsa_i32_pkcs1_vrfy.c \
src/rsa/rsa_i32_priv.c \
src/rsa/rsa_i32_pss_sign.c \
src/rsa/rsa_i32_pss_vrfy.c \
src/rsa/rsa_i32_pub.c \
src/rsa/rsa_i62_keygen.c \
src/rsa/rsa_i62_oaep_decrypt.c \
src/rsa/rsa_i62_oaep_encrypt.c \
src/rsa/rsa_i62_pkcs1_sign.c \
src/rsa/rsa_i62_pkcs1_vrfy.c \
src/rsa/rsa_i62_priv.c \
src/rsa/rsa_i62_pss_sign.c \
src/rsa/rsa_i62_pss_vrfy.c \
src/rsa/rsa_i62_pub.c \
src/rsa/rsa_oaep_pad.c \
src/rsa/rsa_oaep_unpad.c \
src/rsa/rsa_pkcs1_sig_pad.c \
src/rsa/rsa_pkcs1_sig_unpad.c \
src/rsa/rsa_pss_sig_pad.c \
src/rsa/rsa_pss_sig_unpad.c \
src/rsa/rsa_ssl_decrypt.c \
src/ssl/prf.c \
src/ssl/prf_md5sha1.c \
src/ssl/prf_sha256.c \
src/ssl/prf_sha384.c \
src/ssl/ssl_ccert_single_ec.c \
src/ssl/ssl_ccert_single_rsa.c \
src/ssl/ssl_client.c \
src/ssl/ssl_client_default_rsapub.c \
src/ssl/ssl_client_full.c \
src/ssl/ssl_engine.c \
src/ssl/ssl_engine_default_aescbc.c \
src/ssl/ssl_engine_default_aesccm.c \
src/ssl/ssl_engine_default_aesgcm.c \
src/ssl/ssl_engine_default_chapol.c \
src/ssl/ssl_engine_default_descbc.c \
src/ssl/ssl_engine_default_ec.c \
src/ssl/ssl_engine_default_ecdsa.c \
src/ssl/ssl_engine_default_rsavrfy.c \
src/ssl/ssl_hashes.c \
src/ssl/ssl_hs_client.c \
src/ssl/ssl_hs_server.c \
src/ssl/ssl_io.c \
src/ssl/ssl_keyexport.c \
src/ssl/ssl_lru.c \
src/ssl/ssl_rec_cbc.c \
src/ssl/ssl_rec_ccm.c \
src/ssl/ssl_rec_chapol.c \
src/ssl/ssl_rec_gcm.c \
src/ssl/ssl_scert_single_ec.c \
src/ssl/ssl_scert_single_rsa.c \
src/ssl/ssl_server.c \
src/ssl/ssl_server_full_ec.c \
src/ssl/ssl_server_full_rsa.c \
src/ssl/ssl_server_mine2c.c \
src/ssl/ssl_server_mine2g.c \
src/ssl/ssl_server_minf2c.c \
src/ssl/ssl_server_minf2g.c \
src/ssl/ssl_server_minr2g.c \
src/ssl/ssl_server_minu2g.c \
src/ssl/ssl_server_minv2g.c \
src/symcipher/aes_big_cbcdec.c \
src/symcipher/aes_big_cbcenc.c \
src/symcipher/aes_big_ctr.c \
src/symcipher/aes_big_ctrcbc.c \
src/symcipher/aes_big_dec.c \
src/symcipher/aes_big_enc.c \
src/symcipher/aes_common.c \
src/symcipher/aes_ct.c \
src/symcipher/aes_ct64.c \
src/symcipher/aes_ct64_cbcdec.c \
src/symcipher/aes_ct64_cbcenc.c \
src/symcipher/aes_ct64_ctr.c \
src/symcipher/aes_ct64_ctrcbc.c \
src/symcipher/aes_ct64_dec.c \
src/symcipher/aes_ct64_enc.c \
src/symcipher/aes_ct_cbcdec.c \
src/symcipher/aes_ct_cbcenc.c \
src/symcipher/aes_ct_ctr.c \
src/symcipher/aes_ct_ctrcbc.c \
src/symcipher/aes_ct_dec.c \
src/symcipher/aes_ct_enc.c \
src/symcipher/aes_pwr8.c \
src/symcipher/aes_pwr8_cbcdec.c \
src/symcipher/aes_pwr8_cbcenc.c \
src/symcipher/aes_pwr8_ctr.c \
src/symcipher/aes_pwr8_ctrcbc.c \
src/symcipher/aes_small_cbcdec.c \
src/symcipher/aes_small_cbcenc.c \
src/symcipher/aes_small_ctr.c \
src/symcipher/aes_small_ctrcbc.c \
src/symcipher/aes_small_dec.c \
src/symcipher/aes_small_enc.c \
src/symcipher/aes_x86ni.c \
src/symcipher/aes_x86ni_cbcdec.c \
src/symcipher/aes_x86ni_cbcenc.c \
src/symcipher/aes_x86ni_ctr.c \
src/symcipher/aes_x86ni_ctrcbc.c \
src/symcipher/chacha20_ct.c \
src/symcipher/chacha20_sse2.c \
src/symcipher/des_ct.c \
src/symcipher/des_ct_cbcdec.c \
src/symcipher/des_ct_cbcenc.c \
src/symcipher/des_support.c \
src/symcipher/des_tab.c \
src/symcipher/des_tab_cbcdec.c \
src/symcipher/des_tab_cbcenc.c \
src/symcipher/poly1305_ctmul.c \
src/symcipher/poly1305_ctmul32.c \
src/symcipher/poly1305_ctmulq.c \
src/symcipher/poly1305_i15.c \
src/x509/asn1enc.c \
src/x509/encode_ec_pk8der.c \
src/x509/encode_ec_rawder.c \
src/x509/encode_rsa_pk8der.c \
src/x509/encode_rsa_rawder.c \
src/x509/skey_decoder.c \
src/x509/x509_decoder.c \
src/x509/x509_knownkey.c \
src/x509/x509_minimal.c \
src/x509/x509_minimal_full.c"
# Source files for the 'brssl' command-line tool.
toolssrc=" \
tools/brssl.c \
tools/certs.c \
tools/chain.c \
tools/client.c \
tools/errors.c \
tools/files.c \
tools/impl.c \
tools/keys.c \
tools/names.c \
tools/server.c \
tools/skey.c \
tools/sslio.c \
tools/ta.c \
tools/twrch.c \
tools/vector.c \
tools/verify.c \
tools/xmem.c"
# Source files the the 'testcrypto' command-line tool.
testcryptosrc=" \
test/test_crypto.c"
# Source files the the 'testspeed' command-line tool.
testspeedsrc=" \
test/test_speed.c"
# Source files the the 'testx509' command-line tool.
testx509src=" \
test/test_x509.c"
# Public header files.
headerspub=" \
inc/bearssl.h \
inc/bearssl_aead.h \
inc/bearssl_block.h \
inc/bearssl_ec.h \
inc/bearssl_hash.h \
inc/bearssl_hmac.h \
inc/bearssl_kdf.h \
inc/bearssl_pem.h \
inc/bearssl_prf.h \
inc/bearssl_rand.h \
inc/bearssl_rsa.h \
inc/bearssl_ssl.h \
inc/bearssl_x509.h"
# Private header files.
headerspriv=" \
src/config.h \
src/inner.h"
# Header files for the 'brssl' command-line tool.
headerstools=" \
tools/brssl.h"
# T0 compiler source code.
t0compsrc=" \
T0/BlobWriter.cs \
T0/CPU.cs \
T0/CodeElement.cs \
T0/CodeElementJump.cs \
T0/CodeElementUInt.cs \
T0/CodeElementUIntExpr.cs \
T0/CodeElementUIntInt.cs \
T0/CodeElementUIntUInt.cs \
T0/ConstData.cs \
T0/Opcode.cs \
T0/OpcodeCall.cs \
T0/OpcodeConst.cs \
T0/OpcodeGetLocal.cs \
T0/OpcodeJump.cs \
T0/OpcodeJumpIf.cs \
T0/OpcodeJumpIfNot.cs \
T0/OpcodeJumpUncond.cs \
T0/OpcodePutLocal.cs \
T0/OpcodeRet.cs \
T0/SType.cs \
T0/T0Comp.cs \
T0/TPointerBase.cs \
T0/TPointerBlob.cs \
T0/TPointerExpr.cs \
T0/TPointerNull.cs \
T0/TPointerXT.cs \
T0/TValue.cs \
T0/Word.cs \
T0/WordBuilder.cs \
T0/WordData.cs \
T0/WordInterpreted.cs \
T0/WordNative.cs"
t0compkern=" \
T0/kern.t0"
# Function to turn slashes into $P (macro for path separator).
escsep() {
printf '%s' "$1" | sed 's/\//$P/g'
}
# Create rules file.
rm -f Rules.mk
cat > Rules.mk <<EOF
# Automatically generated rules. Use 'mkrules.sh' to modify/regenerate.
EOF
(printf "\nOBJ ="
for f in $coresrc ; do
printf ' \\\n $(OBJDIR)$P%s' "$(basename "$f" .c)\$O"
done
printf "\nOBJBRSSL ="
for f in $toolssrc ; do
printf ' \\\n $(OBJDIR)$P%s' "$(basename "$f" .c)\$O"
done
printf "\nOBJTESTCRYPTO ="
for f in $testcryptosrc ; do
printf ' \\\n $(OBJDIR)$P%s' "$(basename "$f" .c)\$O"
done
printf "\nOBJTESTSPEED ="
for f in $testspeedsrc ; do
printf ' \\\n $(OBJDIR)$P%s' "$(basename "$f" .c)\$O"
done
printf "\nOBJTESTX509 ="
for f in $testx509src ; do
printf ' \\\n $(OBJDIR)$P%s' "$(basename "$f" .c)\$O"
done
printf "\nHEADERSPUB ="
for f in $headerspub ; do
printf " %s" "$(escsep "$f")"
done
printf "\nHEADERSPRIV = %s" '$(HEADERSPUB)'
for f in $headerspriv ; do
printf " %s" "$(escsep "$f")"
done
printf "\nHEADERSTOOLS = %s" '$(HEADERSPUB)'
for f in $headerstools ; do
printf " %s" "$(escsep "$f")"
done
printf "\nT0SRC ="
for f in $t0compsrc ; do
printf " %s" "$(escsep "$f")"
done
printf "\nT0KERN ="
for f in $t0kernsrc ; do
printf " %s" "$(escsep "$f")"
done
printf "\n") >> Rules.mk
cat >> Rules.mk <<EOF
all: \$(STATICLIB) \$(DLL) \$(TOOLS) \$(TESTS)
no:
lib: \$(BEARSSLLIB)
dll: \$(BEARSSLDLL)
tools: \$(BRSSL)
tests: \$(TESTCRYPTO) \$(TESTSPEED) \$(TESTX509)
T0: kT0
kT0: \$(T0COMP) src\$Pssl\$Pssl_hs_common.t0 src\$Pssl\$Pssl_hs_client.t0 src\$Pssl\$Pssl_hs_server.t0 src\$Px509\$Pasn1.t0 src\$Px509\$Pskey_decoder.t0 src\$Px509\$Px509_decoder.t0 src\$Px509\$Px509_minimal.t0
\$(RUNT0COMP) -o src\$Pcodec\$Ppemdec -r br_pem_decoder src\$Pcodec\$Ppemdec.t0
\$(RUNT0COMP) -o src\$Pssl\$Pssl_hs_client -r br_ssl_hs_client src\$Pssl\$Pssl_hs_common.t0 src\$Pssl\$Pssl_hs_client.t0
\$(RUNT0COMP) -o src\$Pssl\$Pssl_hs_server -r br_ssl_hs_server src\$Pssl\$Pssl_hs_common.t0 src\$Pssl\$Pssl_hs_server.t0
\$(RUNT0COMP) -o src\$Px509\$Pskey_decoder -r br_skey_decoder src\$Px509\$Pasn1.t0 src\$Px509\$Pskey_decoder.t0
\$(RUNT0COMP) -o src\$Px509\$Px509_decoder -r br_x509_decoder src\$Px509\$Pasn1.t0 src\$Px509\$Px509_decoder.t0
\$(RUNT0COMP) -o src\$Px509\$Px509_minimal -r br_x509_minimal src\$Px509\$Pasn1.t0 src\$Px509\$Px509_minimal.t0
\$(T0COMP): \$(T0SRC) \$(T0KERN)
\$(MKT0COMP)
clean:
-\$(RM) \$(OBJDIR)\$P*\$O
-\$(RM) \$(BEARSSLLIB) \$(BEARSSLDLL) \$(BRSSL) \$(TESTCRYPTO) \$(TESTSPEED) \$(TESTX509)
\$(OBJDIR):
-\$(MKDIR) \$(OBJDIR)
\$(BEARSSLLIB): \$(OBJDIR) \$(OBJ)
\$(AR) \$(ARFLAGS) \$(AROUT)\$(BEARSSLLIB) \$(OBJ)
\$(BEARSSLDLL): \$(OBJDIR) \$(OBJ)
\$(LDDLL) \$(LDDLLFLAGS) \$(LDDLLOUT)\$(BEARSSLDLL) \$(OBJ)
\$(BRSSL): \$(BEARSSLLIB) \$(OBJBRSSL)
\$(LD) \$(LDFLAGS) \$(LDOUT)\$(BRSSL) \$(OBJBRSSL) \$(BEARSSLLIB)
\$(TESTCRYPTO): \$(BEARSSLLIB) \$(OBJTESTCRYPTO)
\$(LD) \$(LDFLAGS) \$(LDOUT)\$(TESTCRYPTO) \$(OBJTESTCRYPTO) \$(BEARSSLLIB)
\$(TESTSPEED): \$(BEARSSLLIB) \$(OBJTESTSPEED)
\$(LD) \$(LDFLAGS) \$(LDOUT)\$(TESTSPEED) \$(OBJTESTSPEED) \$(BEARSSLLIB)
\$(TESTX509): \$(BEARSSLLIB) \$(OBJTESTX509)
\$(LD) \$(LDFLAGS) \$(LDOUT)\$(TESTX509) \$(OBJTESTX509) \$(BEARSSLLIB)
EOF
(for f in $coresrc ; do
b="$(basename "$f" .c)\$O"
g="$(escsep "$f")"
printf '\n$(OBJDIR)$P%s: %s $(HEADERSPRIV)\n\t$(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$P%s %s\n' "$b" "$g" "$b" "$g"
done
for f in $toolssrc ; do
b="$(basename "$f" .c)\$O"
g="$(escsep "$f")"
printf '\n$(OBJDIR)$P%s: %s $(HEADERSTOOLS)\n\t$(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$P%s %s\n' "$b" "$g" "$b" "$g"
done
for f in $testcryptosrc $testspeedsrc ; do
b="$(basename "$f" .c)\$O"
g="$(escsep "$f")"
printf '\n$(OBJDIR)$P%s: %s $(HEADERSPRIV)\n\t$(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$P%s %s\n' "$b" "$g" "$b" "$g"
done
for f in $testx509src ; do
b="$(basename "$f" .c)\$O"
g="$(escsep "$f")"
printf '\n$(OBJDIR)$P%s: %s $(HEADERSPRIV)\n\t$(CC) $(CFLAGS) $(INCFLAGS) -DSRCDIRNAME=".." $(CCOUT)$(OBJDIR)$P%s %s\n' "$b" "$g" "$b" "$g"
done) >> Rules.mk

View File

@ -0,0 +1,36 @@
This directory contains sample code for using BearSSL.
client_basic.c
A sample client code, that connects to a server, performs a SSL
handshake, sends a basic HTTP GET request, and dumps the complete
answer on stdout.
Compile it against BearSSL headers (in the ../inc directory) and
library (libbearssl.a). This code will validate the server
certificate against two hardcoded trust anchors.
server_basic.c
A sample SSL server, that serves one client at a time. It reads a
single HTTP request (that it does not really parse; it just waits for
the two successive line endings that mark the end of the request),
and pushes a basic response.
Compile it against BearSSL headers (in the ../inc directory) and
library (libbearssl.a). Depending on compilation options (see the
code), it will use one of several certificate chains, that exercise
various combinations of RSA and EC keys and signatures. These
certificate chains link to the trust anchors that are hardcoded
in client_basic.c, so the sample client and the sample server can
be tested against each other.
custom_profile.c
A sample C source file that shows how to write your own client or
server profiles (selections of cipher suites and algorithms).
The .pem files are certificate and keys corresponding to the chains
and anchors used by the sample client and server. They are provided
for reference only; these files are not used by the examples.

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICcTCCAVmgAwIBAgIUbmO7Sc5BfgOM9Ubyiq5hCDWwlLMwDQYJKoZIhvcNAQELBQAwJzELMAkG
A1UEBhMCQ0ExGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAeFw0xMDAxMDEwMDAwMDBaFw0zNzEy
MzEyMzU5NTlaMCExCzAJBgNVBAYTAkNBMRIwEAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIB
BggqhkjOPQMBBwNCAARfOJ2n/02Kr/Y0OUYa/Drf9COqqer7xQjeAI6+eaU3WExt3QHKq0ffibbH
Fx84/B0gFN1FwOCPk044C/zpmaFJo2YwZDAfBgNVHSMEGDAWgBR8z6PGKffzxaoZ0MAW6+BAD85E
pzAdBgNVHQ4EFgQUww6GqnW0FcDllQkyvl6SdankRJswDAYDVR0TAQH/BAIwADAUBgNVHREEDTAL
gglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAI6JY6ebqBCOnhjQpHrdLIIWjwsO1cpXu19v
/FcowCG6rZSoF0JF1zH3hFcZRiQ8x0k4P0h6CRrrUbrFdY5MsiWwxyI+5+VG27E2/BuFUbDtgxbw
OnnaXShq7mogTLBwXrDtem0tGsm0ccLEox0lhjBUsZgmwVHg+DGtZ0id5qFSOyBHyXDagLWk9D9y
azcwVzksRptE8dlOu6Zf45rFf2y2Zcu/QHKS0Gj2rnl+JMFbaDAoU3FhevQ2ezvCtuwf3DBABA3q
swrPddO9nqtxcWh/pUFSAOmzruQe8btpxjvV3tLCJWkIPDfM94Jq5ah7agLavaQBMzPz3kYA7HXP
4H0=
-----END CERTIFICATE-----

View File

@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBsDCCAVagAwIBAgIUHE0AkWniRqyQfGRcU/H/t8HLbnowCgYIKoZIzj0EAwIwJzELMAkGA1UE
BhMCQ0ExGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAeFw0xMDAxMDEwMDAwMDBaFw0zNzEyMzEy
MzU5NTlaMCExCzAJBgNVBAYTAkNBMRIwEAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggq
hkjOPQMBBwNCAARfOJ2n/02Kr/Y0OUYa/Drf9COqqer7xQjeAI6+eaU3WExt3QHKq0ffibbHFx84
/B0gFN1FwOCPk044C/zpmaFJo2YwZDAfBgNVHSMEGDAWgBTw0PEi+XpIFwZ7Pb249c1VnFw+cDAd
BgNVHQ4EFgQUww6GqnW0FcDllQkyvl6SdankRJswDAYDVR0TAQH/BAIwADAUBgNVHREEDTALggls
b2NhbGhvc3QwCgYIKoZIzj0EAwIDSAAwRQIhAJH79ATQ5S4B1IzwF2IP3MyAyhjEQHwnA8s0Aw2b
yFlNAiAFVWni2KFAMzQOfkkyZB0/ax/QLbcvUgRWr9M3j4eZog==
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIIDPDCCAiSgAwIBAgIUWNq6Ns3toNpcEDNzjgxkknmSrwMwDQYJKoZIhvcNAQELBQAwJzELMAkG
A1UEBhMCQ0ExGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAeFw0xMDAxMDEwMDAwMDBaFw0zNzEy
MzEyMzU5NTlaMCExCzAJBgNVBAYTAkNBMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDUeh0nuis6Z7KRavvng0TK7Rx1rd1Ng2LWqmiVsiQhexWuKplo
Fe1m8LhY59P1LsbZKl7nDi7n/GdZwMhhfUukb92f2ciFh2THuhoPKdSWqHiaa2IgqTLQ7qmMKGFH
olAqY/Yh3trY1fB/xQCCcOajv1yJJ09RkncDw7DMLjvsI/IvU0GviZP/0oCxQ5fe1hmgkhJ6PWZ5
4cG84Xdwoos9RoRTP+ROQkE3kh4f/Tiz9++HOYDTVs/04BPeZLBypAOExEHtb/o+4soEINLX3CyC
K3ribaEcSNvPiU80lz0oqFPa58HhcxWjMHZ/jyNCFD1RNNJarTyby8j+f26OQPO9AgMBAAGjZjBk
MB8GA1UdIwQYMBaAFMUBrXzmY8mcF1/FoqfhUF/o9ajGMB0GA1UdDgQWBBTFAa185mPJnBdfxaKn
4VBf6PWoxjAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsF
AAOCAQEAcbNdIcIO19DG+Epzh00iAifQx/j9Gm1iWIIIdiAHwEiS8+mYWusNTlaVY2hNq9QAduA3
zwsRYVlc3valFFnZJZ9Z2dNehqwdpiwyQhkyE0ALVM1nJra9tJakyh9/N9aodes6gVEwuflKAW/R
1u1P3z8wYAZnko5hhV8atYyzD2Gp+t9dxGQA6oexM199y6OFJG4sZTvqcz+G0/3o5ALGYWomF1IB
JVx/qM5pH6xhLLcEr/2kepnLJhVM/3TUcwxXDCbr1yrcXMNBu8Lzzha9jnv76d+rIQ2Rs43Yz8j0
SbnQ4xZwP7Pe1Acl+kZEUolNicjiyrUzf8chvSjv/mZ0Aw==
-----END CERTIFICATE-----

View File

@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBqTCCAU6gAwIBAgIUINPr4oz+2uajLF478mY6KzZ7sMowCgYIKoZIzj0EAwIwHDELMAkGA1UE
BhMCQ0ExDTALBgNVBAMTBFJvb3QwHhcNMTAwMTAxMDAwMDAwWhcNMzcxMjMxMjM1OTU5WjAnMQsw
CQYDVQQGEwJDQTEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEcC6SggEXbG2r4dFjCUhJ0qY1UtM8c7uyiDeYh/GN4Oxlmg4T9e2RYci2bTOEbq6OVYDN
SZ4Hv9CunebQsycWoaNjMGEwHwYDVR0jBBgwFoAUlUG04meq8X+8j3nzaBRaa5IWokAwHQYDVR0O
BBYEFPDQ8SL5ekgXBns9vbj1zVWcXD5wMA4GA1UdDwEB/wQEAwIAhjAPBgNVHRMBAf8EBTADAQH/
MAoGCCqGSM49BAMCA0kAMEYCIQCF40ZomdYCellmHLdPNS0INjhhfgVI2GlDH+tW6a0GDgIhAIJw
tGIDSUbIVFkF2XjbUxzgbmb1DxQ7yS04EnCRVvmp
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIIDNDCCAhygAwIBAgIUcA9g7vAHmpxprJdiJk9dBbb5j0gwDQYJKoZIhvcNAQELBQAwHDELMAkG
A1UEBhMCQ0ExDTALBgNVBAMTBFJvb3QwHhcNMTAwMTAxMDAwMDAwWhcNMzcxMjMxMjM1OTU5WjAn
MQswCQYDVQQGEwJDQTEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAs+hrr5wWUuOBDFCrJc7MDcfyH39Q3yxcNdZiLmMnQafkU6hLJ/oTkaP6
CUovO17Pd7OKwc1JlZx1DWR07+TXS7mhm2jSMHFI6vdLFN8/R6nYu+yPKMz637QflHyW/AgFKPno
9C8v7mKcijrghVhgtg8tMLTAQVSRTB9frfEZ8MAipn3YP3k0WUJ7W7VBxGR/Us88NyKhL3kllCRB
wj/6x3X7SLUNGKf0VPMubthDWMSrUOgFrZG2HgF1s1Sc3qCZFfus8VyXSVHM71gSb3NrszQUAQ9a
nfqq1pPT4urDq7xO7cxRobj4lLa0LKiGKx/2UUMpUl4TibNqeGBOTsAbpQIDAQABo2MwYTAfBgNV
HSMEGDAWgBTDCry0kGOWkkW8J6DwWIkq1XgAEjAdBgNVHQ4EFgQUfM+jxin388WqGdDAFuvgQA/O
RKcwDgYDVR0PAQH/BAQDAgCGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFQ7
9OrG5OjAWxKyrfq9qfRiA61XTG8Hp0c1dT5IoltxEAGPk5mdp0fjjj6vLboG/tTkl7wQjaalOjzm
Ics72hPjSiPrvLqlkJGtVW7V3YVLayfSOXYGLtQjW7tVtUk/fS8hy5Z1GZmpmfELuz7HEKeLelK5
SeQUCHjnPdmYV9r/2rmNZnWAtV2532ll2xbnHsRA5EaKHnYyFueDZ9p4VqsPTFzxcNpmIPT4D/bc
L3KXa3hAeZ1bbb4DznBCqCpxEd8ugQHqhhKRT9AY7YSkSDC5uXtWPu+N4R/9kLJEhVhvpzB0fPGu
jJk/8U1XxZVowjay7MJoesCBqVUF58+vUKw=
-----END CERTIFICATE-----

View File

@ -0,0 +1,9 @@
-----BEGIN CERTIFICATE-----
MIIBijCCATCgAwIBAgIBCTAKBggqhkjOPQQDAjAcMQswCQYDVQQGEwJDQTENMAsGA1UEAxMEUm9v
dDAeFw0xMDAxMDEwMDAwMDBaFw0zNzEyMzEyMzU5NTlaMBwxCzAJBgNVBAYTAkNBMQ0wCwYDVQQD
EwRSb290MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcXS6q7kwLoHV5Vf58yBoDJz5ZNu0IA1t
6kDQSm5C/baaaCVE9t97xPze3Xu7xdt8dj9BZkBu26eHwuXYxfN/jaNjMGEwHwYDVR0jBBgwFoAU
lUG04meq8X+8j3nzaBRaa5IWokAwHQYDVR0OBBYEFJVBtOJnqvF/vI9582gUWmuSFqJAMA4GA1Ud
DwEB/wQEAwIAhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQCz1GCIAoRtqU2h
x62hec7E+/XxnUGDORWnkliiGrcmxQIgNPq9NHD7ts0xYjTwZsd0bN62+iY93lM4LHbkNV9q/gA=
-----END CERTIFICATE-----

View File

@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIIDFjCCAf6gAwIBAgIBCDANBgkqhkiG9w0BAQsFADAcMQswCQYDVQQGEwJDQTENMAsGA1UEAxME
Um9vdDAeFw0xMDAxMDEwMDAwMDBaFw0zNzEyMzEyMzU5NTlaMBwxCzAJBgNVBAYTAkNBMQ0wCwYD
VQQDEwRSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAttk01FD9s696c/HOOL9d
b0Xh/U6xmMZggybSF9HFt5qjwd5jOZec8F5cyBwXuYgZbfC2LjBQoVRuk8DbzzDLnx4nefHDmVI1
qj2237CtfMtJzcDt52YQKunOKB8hUPp3TC3a7zxY606/zun7Gtqjg6PNo8qTgNza8xfMeqszgJyy
1H9GP8U83GGUtycpbiq8Wwk21MY7Deu+ztsdHLwQanFxs/LKKJp38orsQu+xSo7i8hoyKs3ApkYs
msKFN5F/RqGTgaF0Zt+6szkgkZP6HaGohefk+Qf2EPaoJwG2fxLDQMPJ4rCrSRg6ZLZZt5W1ljbf
ImmqcmpUTicpow6XFQIDAQABo2MwYTAfBgNVHSMEGDAWgBTDCry0kGOWkkW8J6DwWIkq1XgAEjAd
BgNVHQ4EFgQUwwq8tJBjlpJFvCeg8FiJKtV4ABIwDgYDVR0PAQH/BAQDAgCGMA8GA1UdEwEB/wQF
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAA7SaR2V1Gx71RiL5Cdfr15jkU88snnm+v+0PvIfQrNP
4RzKJkaD3j//oZf6Hr2yH6c7Bi3OhCxBFNbXjDXiAXVRoTjOSxNSwVq43utl9Z4IKAZzQlEYW5S5
U0oskEq2q6jDEWoj8lUtQW4GAVuZhq7lNs0jJJu84IBsxHJFgZJ/7+LHFLXs+vQkz3hjzMZ7gIt+
lwXI/gdY9ld1QB6WLLIzxs7zid+Z0LZTYi851vbmMwUqgL8V5Np0Q0EVHHy1c6LQ0hj1kVLay2ZN
d2dsUMCQJI5EF2kWon+xFDpAtv0vUT2xuMkYFhjS/aBxzevWCsXuUQphBYaIGli8P68NNPo=
-----END CERTIFICATE-----

View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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 "bearssl.h"
/*
* A sample server certificate chain with a single intermediate CA.
* Certificate key type: EC
* Signing algorithm for both certificates: RSA
*/
static const unsigned char CERT0[] = {
0x30, 0x82, 0x02, 0x71, 0x30, 0x82, 0x01, 0x59, 0xA0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x14, 0x6E, 0x63, 0xBB, 0x49, 0xCE, 0x41, 0x7E, 0x03, 0x8C,
0xF5, 0x46, 0xF2, 0x8A, 0xAE, 0x61, 0x08, 0x35, 0xB0, 0x94, 0xB3, 0x30,
0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
0x05, 0x00, 0x30, 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55,
0x04, 0x03, 0x13, 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D, 0x65, 0x64,
0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x31,
0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A,
0x17, 0x0D, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39,
0x35, 0x39, 0x5A, 0x30, 0x21, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
0x55, 0x04, 0x03, 0x13, 0x09, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x68, 0x6F,
0x73, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE,
0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01,
0x07, 0x03, 0x42, 0x00, 0x04, 0x5F, 0x38, 0x9D, 0xA7, 0xFF, 0x4D, 0x8A,
0xAF, 0xF6, 0x34, 0x39, 0x46, 0x1A, 0xFC, 0x3A, 0xDF, 0xF4, 0x23, 0xAA,
0xA9, 0xEA, 0xFB, 0xC5, 0x08, 0xDE, 0x00, 0x8E, 0xBE, 0x79, 0xA5, 0x37,
0x58, 0x4C, 0x6D, 0xDD, 0x01, 0xCA, 0xAB, 0x47, 0xDF, 0x89, 0xB6, 0xC7,
0x17, 0x1F, 0x38, 0xFC, 0x1D, 0x20, 0x14, 0xDD, 0x45, 0xC0, 0xE0, 0x8F,
0x93, 0x4E, 0x38, 0x0B, 0xFC, 0xE9, 0x99, 0xA1, 0x49, 0xA3, 0x66, 0x30,
0x64, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16,
0x80, 0x14, 0x7C, 0xCF, 0xA3, 0xC6, 0x29, 0xF7, 0xF3, 0xC5, 0xAA, 0x19,
0xD0, 0xC0, 0x16, 0xEB, 0xE0, 0x40, 0x0F, 0xCE, 0x44, 0xA7, 0x30, 0x1D,
0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xC3, 0x0E, 0x86,
0xAA, 0x75, 0xB4, 0x15, 0xC0, 0xE5, 0x95, 0x09, 0x32, 0xBE, 0x5E, 0x92,
0x75, 0xA9, 0xE4, 0x44, 0x9B, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13,
0x01, 0x01, 0xFF, 0x04, 0x02, 0x30, 0x00, 0x30, 0x14, 0x06, 0x03, 0x55,
0x1D, 0x11, 0x04, 0x0D, 0x30, 0x0B, 0x82, 0x09, 0x6C, 0x6F, 0x63, 0x61,
0x6C, 0x68, 0x6F, 0x73, 0x74, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48,
0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
0x00, 0x8E, 0x89, 0x63, 0xA7, 0x9B, 0xA8, 0x10, 0x8E, 0x9E, 0x18, 0xD0,
0xA4, 0x7A, 0xDD, 0x2C, 0x82, 0x16, 0x8F, 0x0B, 0x0E, 0xD5, 0xCA, 0x57,
0xBB, 0x5F, 0x6F, 0xFC, 0x57, 0x28, 0xC0, 0x21, 0xBA, 0xAD, 0x94, 0xA8,
0x17, 0x42, 0x45, 0xD7, 0x31, 0xF7, 0x84, 0x57, 0x19, 0x46, 0x24, 0x3C,
0xC7, 0x49, 0x38, 0x3F, 0x48, 0x7A, 0x09, 0x1A, 0xEB, 0x51, 0xBA, 0xC5,
0x75, 0x8E, 0x4C, 0xB2, 0x25, 0xB0, 0xC7, 0x22, 0x3E, 0xE7, 0xE5, 0x46,
0xDB, 0xB1, 0x36, 0xFC, 0x1B, 0x85, 0x51, 0xB0, 0xED, 0x83, 0x16, 0xF0,
0x3A, 0x79, 0xDA, 0x5D, 0x28, 0x6A, 0xEE, 0x6A, 0x20, 0x4C, 0xB0, 0x70,
0x5E, 0xB0, 0xED, 0x7A, 0x6D, 0x2D, 0x1A, 0xC9, 0xB4, 0x71, 0xC2, 0xC4,
0xA3, 0x1D, 0x25, 0x86, 0x30, 0x54, 0xB1, 0x98, 0x26, 0xC1, 0x51, 0xE0,
0xF8, 0x31, 0xAD, 0x67, 0x48, 0x9D, 0xE6, 0xA1, 0x52, 0x3B, 0x20, 0x47,
0xC9, 0x70, 0xDA, 0x80, 0xB5, 0xA4, 0xF4, 0x3F, 0x72, 0x6B, 0x37, 0x30,
0x57, 0x39, 0x2C, 0x46, 0x9B, 0x44, 0xF1, 0xD9, 0x4E, 0xBB, 0xA6, 0x5F,
0xE3, 0x9A, 0xC5, 0x7F, 0x6C, 0xB6, 0x65, 0xCB, 0xBF, 0x40, 0x72, 0x92,
0xD0, 0x68, 0xF6, 0xAE, 0x79, 0x7E, 0x24, 0xC1, 0x5B, 0x68, 0x30, 0x28,
0x53, 0x71, 0x61, 0x7A, 0xF4, 0x36, 0x7B, 0x3B, 0xC2, 0xB6, 0xEC, 0x1F,
0xDC, 0x30, 0x40, 0x04, 0x0D, 0xEA, 0xB3, 0x0A, 0xCF, 0x75, 0xD3, 0xBD,
0x9E, 0xAB, 0x71, 0x71, 0x68, 0x7F, 0xA5, 0x41, 0x52, 0x00, 0xE9, 0xB3,
0xAE, 0xE4, 0x1E, 0xF1, 0xBB, 0x69, 0xC6, 0x3B, 0xD5, 0xDE, 0xD2, 0xC2,
0x25, 0x69, 0x08, 0x3C, 0x37, 0xCC, 0xF7, 0x82, 0x6A, 0xE5, 0xA8, 0x7B,
0x6A, 0x02, 0xDA, 0xBD, 0xA4, 0x01, 0x33, 0x33, 0xF3, 0xDE, 0x46, 0x00,
0xEC, 0x75, 0xCF, 0xE0, 0x7D
};
static const unsigned char CERT1[] = {
0x30, 0x82, 0x03, 0x34, 0x30, 0x82, 0x02, 0x1C, 0xA0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x14, 0x70, 0x0F, 0x60, 0xEE, 0xF0, 0x07, 0x9A, 0x9C, 0x69,
0xAC, 0x97, 0x62, 0x26, 0x4F, 0x5D, 0x05, 0xB6, 0xF9, 0x8F, 0x48, 0x30,
0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
0x05, 0x00, 0x30, 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55,
0x04, 0x03, 0x13, 0x04, 0x52, 0x6F, 0x6F, 0x74, 0x30, 0x1E, 0x17, 0x0D,
0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x5A, 0x17, 0x0D, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35,
0x39, 0x35, 0x39, 0x5A, 0x30, 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06,
0x03, 0x55, 0x04, 0x03, 0x13, 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D,
0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01,
0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01,
0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB3, 0xE8, 0x6B, 0xAF, 0x9C, 0x16,
0x52, 0xE3, 0x81, 0x0C, 0x50, 0xAB, 0x25, 0xCE, 0xCC, 0x0D, 0xC7, 0xF2,
0x1F, 0x7F, 0x50, 0xDF, 0x2C, 0x5C, 0x35, 0xD6, 0x62, 0x2E, 0x63, 0x27,
0x41, 0xA7, 0xE4, 0x53, 0xA8, 0x4B, 0x27, 0xFA, 0x13, 0x91, 0xA3, 0xFA,
0x09, 0x4A, 0x2F, 0x3B, 0x5E, 0xCF, 0x77, 0xB3, 0x8A, 0xC1, 0xCD, 0x49,
0x95, 0x9C, 0x75, 0x0D, 0x64, 0x74, 0xEF, 0xE4, 0xD7, 0x4B, 0xB9, 0xA1,
0x9B, 0x68, 0xD2, 0x30, 0x71, 0x48, 0xEA, 0xF7, 0x4B, 0x14, 0xDF, 0x3F,
0x47, 0xA9, 0xD8, 0xBB, 0xEC, 0x8F, 0x28, 0xCC, 0xFA, 0xDF, 0xB4, 0x1F,
0x94, 0x7C, 0x96, 0xFC, 0x08, 0x05, 0x28, 0xF9, 0xE8, 0xF4, 0x2F, 0x2F,
0xEE, 0x62, 0x9C, 0x8A, 0x3A, 0xE0, 0x85, 0x58, 0x60, 0xB6, 0x0F, 0x2D,
0x30, 0xB4, 0xC0, 0x41, 0x54, 0x91, 0x4C, 0x1F, 0x5F, 0xAD, 0xF1, 0x19,
0xF0, 0xC0, 0x22, 0xA6, 0x7D, 0xD8, 0x3F, 0x79, 0x34, 0x59, 0x42, 0x7B,
0x5B, 0xB5, 0x41, 0xC4, 0x64, 0x7F, 0x52, 0xCF, 0x3C, 0x37, 0x22, 0xA1,
0x2F, 0x79, 0x25, 0x94, 0x24, 0x41, 0xC2, 0x3F, 0xFA, 0xC7, 0x75, 0xFB,
0x48, 0xB5, 0x0D, 0x18, 0xA7, 0xF4, 0x54, 0xF3, 0x2E, 0x6E, 0xD8, 0x43,
0x58, 0xC4, 0xAB, 0x50, 0xE8, 0x05, 0xAD, 0x91, 0xB6, 0x1E, 0x01, 0x75,
0xB3, 0x54, 0x9C, 0xDE, 0xA0, 0x99, 0x15, 0xFB, 0xAC, 0xF1, 0x5C, 0x97,
0x49, 0x51, 0xCC, 0xEF, 0x58, 0x12, 0x6F, 0x73, 0x6B, 0xB3, 0x34, 0x14,
0x01, 0x0F, 0x5A, 0x9D, 0xFA, 0xAA, 0xD6, 0x93, 0xD3, 0xE2, 0xEA, 0xC3,
0xAB, 0xBC, 0x4E, 0xED, 0xCC, 0x51, 0xA1, 0xB8, 0xF8, 0x94, 0xB6, 0xB4,
0x2C, 0xA8, 0x86, 0x2B, 0x1F, 0xF6, 0x51, 0x43, 0x29, 0x52, 0x5E, 0x13,
0x89, 0xB3, 0x6A, 0x78, 0x60, 0x4E, 0x4E, 0xC0, 0x1B, 0xA5, 0x02, 0x03,
0x01, 0x00, 0x01, 0xA3, 0x63, 0x30, 0x61, 0x30, 0x1F, 0x06, 0x03, 0x55,
0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xC3, 0x0A, 0xBC, 0xB4,
0x90, 0x63, 0x96, 0x92, 0x45, 0xBC, 0x27, 0xA0, 0xF0, 0x58, 0x89, 0x2A,
0xD5, 0x78, 0x00, 0x12, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04,
0x16, 0x04, 0x14, 0x7C, 0xCF, 0xA3, 0xC6, 0x29, 0xF7, 0xF3, 0xC5, 0xAA,
0x19, 0xD0, 0xC0, 0x16, 0xEB, 0xE0, 0x40, 0x0F, 0xCE, 0x44, 0xA7, 0x30,
0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03,
0x02, 0x00, 0x86, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01,
0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09,
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03,
0x82, 0x01, 0x01, 0x00, 0x54, 0x3B, 0xF4, 0xEA, 0xC6, 0xE4, 0xE8, 0xC0,
0x5B, 0x12, 0xB2, 0xAD, 0xFA, 0xBD, 0xA9, 0xF4, 0x62, 0x03, 0xAD, 0x57,
0x4C, 0x6F, 0x07, 0xA7, 0x47, 0x35, 0x75, 0x3E, 0x48, 0xA2, 0x5B, 0x71,
0x10, 0x01, 0x8F, 0x93, 0x99, 0x9D, 0xA7, 0x47, 0xE3, 0x8E, 0x3E, 0xAF,
0x2D, 0xBA, 0x06, 0xFE, 0xD4, 0xE4, 0x97, 0xBC, 0x10, 0x8D, 0xA6, 0xA5,
0x3A, 0x3C, 0xE6, 0x21, 0xCB, 0x3B, 0xDA, 0x13, 0xE3, 0x4A, 0x23, 0xEB,
0xBC, 0xBA, 0xA5, 0x90, 0x91, 0xAD, 0x55, 0x6E, 0xD5, 0xDD, 0x85, 0x4B,
0x6B, 0x27, 0xD2, 0x39, 0x76, 0x06, 0x2E, 0xD4, 0x23, 0x5B, 0xBB, 0x55,
0xB5, 0x49, 0x3F, 0x7D, 0x2F, 0x21, 0xCB, 0x96, 0x75, 0x19, 0x99, 0xA9,
0x99, 0xF1, 0x0B, 0xBB, 0x3E, 0xC7, 0x10, 0xA7, 0x8B, 0x7A, 0x52, 0xB9,
0x49, 0xE4, 0x14, 0x08, 0x78, 0xE7, 0x3D, 0xD9, 0x98, 0x57, 0xDA, 0xFF,
0xDA, 0xB9, 0x8D, 0x66, 0x75, 0x80, 0xB5, 0x5D, 0xB9, 0xDF, 0x69, 0x65,
0xDB, 0x16, 0xE7, 0x1E, 0xC4, 0x40, 0xE4, 0x46, 0x8A, 0x1E, 0x76, 0x32,
0x16, 0xE7, 0x83, 0x67, 0xDA, 0x78, 0x56, 0xAB, 0x0F, 0x4C, 0x5C, 0xF1,
0x70, 0xDA, 0x66, 0x20, 0xF4, 0xF8, 0x0F, 0xF6, 0xDC, 0x2F, 0x72, 0x97,
0x6B, 0x78, 0x40, 0x79, 0x9D, 0x5B, 0x6D, 0xBE, 0x03, 0xCE, 0x70, 0x42,
0xA8, 0x2A, 0x71, 0x11, 0xDF, 0x2E, 0x81, 0x01, 0xEA, 0x86, 0x12, 0x91,
0x4F, 0xD0, 0x18, 0xED, 0x84, 0xA4, 0x48, 0x30, 0xB9, 0xB9, 0x7B, 0x56,
0x3E, 0xEF, 0x8D, 0xE1, 0x1F, 0xFD, 0x90, 0xB2, 0x44, 0x85, 0x58, 0x6F,
0xA7, 0x30, 0x74, 0x7C, 0xF1, 0xAE, 0x8C, 0x99, 0x3F, 0xF1, 0x4D, 0x57,
0xC5, 0x95, 0x68, 0xC2, 0x36, 0xB2, 0xEC, 0xC2, 0x68, 0x7A, 0xC0, 0x81,
0xA9, 0x55, 0x05, 0xE7, 0xCF, 0xAF, 0x50, 0xAC
};
static const br_x509_certificate CHAIN[] = {
{ (unsigned char *)CERT0, sizeof CERT0 },
{ (unsigned char *)CERT1, sizeof CERT1 }
};
#define CHAIN_LEN 2

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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 "bearssl.h"
/*
* A sample server certificate chain with a single intermediate CA.
* Certificate key type: EC
* Signing algorithm for both certificates: ECDSA
*/
static const unsigned char CERT0[] = {
0x30, 0x82, 0x01, 0xB0, 0x30, 0x82, 0x01, 0x56, 0xA0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x14, 0x1C, 0x4D, 0x00, 0x91, 0x69, 0xE2, 0x46, 0xAC, 0x90,
0x7C, 0x64, 0x5C, 0x53, 0xF1, 0xFF, 0xB7, 0xC1, 0xCB, 0x6E, 0x7A, 0x30,
0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30,
0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x74,
0x65, 0x20, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x30, 0x30, 0x31,
0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x33,
0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5A,
0x30, 0x21, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x43, 0x41, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03,
0x13, 0x09, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x68, 0x6F, 0x73, 0x74, 0x30,
0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42,
0x00, 0x04, 0x5F, 0x38, 0x9D, 0xA7, 0xFF, 0x4D, 0x8A, 0xAF, 0xF6, 0x34,
0x39, 0x46, 0x1A, 0xFC, 0x3A, 0xDF, 0xF4, 0x23, 0xAA, 0xA9, 0xEA, 0xFB,
0xC5, 0x08, 0xDE, 0x00, 0x8E, 0xBE, 0x79, 0xA5, 0x37, 0x58, 0x4C, 0x6D,
0xDD, 0x01, 0xCA, 0xAB, 0x47, 0xDF, 0x89, 0xB6, 0xC7, 0x17, 0x1F, 0x38,
0xFC, 0x1D, 0x20, 0x14, 0xDD, 0x45, 0xC0, 0xE0, 0x8F, 0x93, 0x4E, 0x38,
0x0B, 0xFC, 0xE9, 0x99, 0xA1, 0x49, 0xA3, 0x66, 0x30, 0x64, 0x30, 0x1F,
0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xF0,
0xD0, 0xF1, 0x22, 0xF9, 0x7A, 0x48, 0x17, 0x06, 0x7B, 0x3D, 0xBD, 0xB8,
0xF5, 0xCD, 0x55, 0x9C, 0x5C, 0x3E, 0x70, 0x30, 0x1D, 0x06, 0x03, 0x55,
0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xC3, 0x0E, 0x86, 0xAA, 0x75, 0xB4,
0x15, 0xC0, 0xE5, 0x95, 0x09, 0x32, 0xBE, 0x5E, 0x92, 0x75, 0xA9, 0xE4,
0x44, 0x9B, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF,
0x04, 0x02, 0x30, 0x00, 0x30, 0x14, 0x06, 0x03, 0x55, 0x1D, 0x11, 0x04,
0x0D, 0x30, 0x0B, 0x82, 0x09, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x68, 0x6F,
0x73, 0x74, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04,
0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0x91, 0xFB,
0xF4, 0x04, 0xD0, 0xE5, 0x2E, 0x01, 0xD4, 0x8C, 0xF0, 0x17, 0x62, 0x0F,
0xDC, 0xCC, 0x80, 0xCA, 0x18, 0xC4, 0x40, 0x7C, 0x27, 0x03, 0xCB, 0x34,
0x03, 0x0D, 0x9B, 0xC8, 0x59, 0x4D, 0x02, 0x20, 0x05, 0x55, 0x69, 0xE2,
0xD8, 0xA1, 0x40, 0x33, 0x34, 0x0E, 0x7E, 0x49, 0x32, 0x64, 0x1D, 0x3F,
0x6B, 0x1F, 0xD0, 0x2D, 0xB7, 0x2F, 0x52, 0x04, 0x56, 0xAF, 0xD3, 0x37,
0x8F, 0x87, 0x99, 0xA2
};
static const unsigned char CERT1[] = {
0x30, 0x82, 0x01, 0xA9, 0x30, 0x82, 0x01, 0x4E, 0xA0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x14, 0x20, 0xD3, 0xEB, 0xE2, 0x8C, 0xFE, 0xDA, 0xE6, 0xA3,
0x2C, 0x5E, 0x3B, 0xF2, 0x66, 0x3A, 0x2B, 0x36, 0x7B, 0xB0, 0xCA, 0x30,
0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30,
0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
0x04, 0x52, 0x6F, 0x6F, 0x74, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x30, 0x30,
0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x17, 0x0D,
0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39,
0x5A, 0x30, 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04,
0x03, 0x13, 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D, 0x65, 0x64, 0x69,
0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48,
0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x70, 0x2E, 0x92,
0x82, 0x01, 0x17, 0x6C, 0x6D, 0xAB, 0xE1, 0xD1, 0x63, 0x09, 0x48, 0x49,
0xD2, 0xA6, 0x35, 0x52, 0xD3, 0x3C, 0x73, 0xBB, 0xB2, 0x88, 0x37, 0x98,
0x87, 0xF1, 0x8D, 0xE0, 0xEC, 0x65, 0x9A, 0x0E, 0x13, 0xF5, 0xED, 0x91,
0x61, 0xC8, 0xB6, 0x6D, 0x33, 0x84, 0x6E, 0xAE, 0x8E, 0x55, 0x80, 0xCD,
0x49, 0x9E, 0x07, 0xBF, 0xD0, 0xAE, 0x9D, 0xE6, 0xD0, 0xB3, 0x27, 0x16,
0xA1, 0xA3, 0x63, 0x30, 0x61, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23,
0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x95, 0x41, 0xB4, 0xE2, 0x67, 0xAA,
0xF1, 0x7F, 0xBC, 0x8F, 0x79, 0xF3, 0x68, 0x14, 0x5A, 0x6B, 0x92, 0x16,
0xA2, 0x40, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04,
0x14, 0xF0, 0xD0, 0xF1, 0x22, 0xF9, 0x7A, 0x48, 0x17, 0x06, 0x7B, 0x3D,
0xBD, 0xB8, 0xF5, 0xCD, 0x55, 0x9C, 0x5C, 0x3E, 0x70, 0x30, 0x0E, 0x06,
0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, 0x00,
0x86, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04,
0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86,
0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02,
0x21, 0x00, 0x85, 0xE3, 0x46, 0x68, 0x99, 0xD6, 0x02, 0x7A, 0x59, 0x66,
0x1C, 0xB7, 0x4F, 0x35, 0x2D, 0x08, 0x36, 0x38, 0x61, 0x7E, 0x05, 0x48,
0xD8, 0x69, 0x43, 0x1F, 0xEB, 0x56, 0xE9, 0xAD, 0x06, 0x0E, 0x02, 0x21,
0x00, 0x82, 0x70, 0xB4, 0x62, 0x03, 0x49, 0x46, 0xC8, 0x54, 0x59, 0x05,
0xD9, 0x78, 0xDB, 0x53, 0x1C, 0xE0, 0x6E, 0x66, 0xF5, 0x0F, 0x14, 0x3B,
0xC9, 0x2D, 0x38, 0x12, 0x70, 0x91, 0x56, 0xF9, 0xA9
};
static const br_x509_certificate CHAIN[] = {
{ (unsigned char *)CERT0, sizeof CERT0 },
{ (unsigned char *)CERT1, sizeof CERT1 }
};
#define CHAIN_LEN 2

View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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 "bearssl.h"
/*
* A sample server certificate chain with a single intermediate CA.
* Certificate key type: RSA
* Signing algorithm for both certificates: RSA
*/
static const unsigned char CERT0[] = {
0x30, 0x82, 0x03, 0x3C, 0x30, 0x82, 0x02, 0x24, 0xA0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x14, 0x58, 0xDA, 0xBA, 0x36, 0xCD, 0xED, 0xA0, 0xDA, 0x5C,
0x10, 0x33, 0x73, 0x8E, 0x0C, 0x64, 0x92, 0x79, 0x92, 0xAF, 0x03, 0x30,
0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
0x05, 0x00, 0x30, 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55,
0x04, 0x03, 0x13, 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D, 0x65, 0x64,
0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x31,
0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A,
0x17, 0x0D, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39,
0x35, 0x39, 0x5A, 0x30, 0x21, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
0x55, 0x04, 0x03, 0x13, 0x09, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x68, 0x6F,
0x73, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86,
0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xD4,
0x7A, 0x1D, 0x27, 0xBA, 0x2B, 0x3A, 0x67, 0xB2, 0x91, 0x6A, 0xFB, 0xE7,
0x83, 0x44, 0xCA, 0xED, 0x1C, 0x75, 0xAD, 0xDD, 0x4D, 0x83, 0x62, 0xD6,
0xAA, 0x68, 0x95, 0xB2, 0x24, 0x21, 0x7B, 0x15, 0xAE, 0x2A, 0x99, 0x68,
0x15, 0xED, 0x66, 0xF0, 0xB8, 0x58, 0xE7, 0xD3, 0xF5, 0x2E, 0xC6, 0xD9,
0x2A, 0x5E, 0xE7, 0x0E, 0x2E, 0xE7, 0xFC, 0x67, 0x59, 0xC0, 0xC8, 0x61,
0x7D, 0x4B, 0xA4, 0x6F, 0xDD, 0x9F, 0xD9, 0xC8, 0x85, 0x87, 0x64, 0xC7,
0xBA, 0x1A, 0x0F, 0x29, 0xD4, 0x96, 0xA8, 0x78, 0x9A, 0x6B, 0x62, 0x20,
0xA9, 0x32, 0xD0, 0xEE, 0xA9, 0x8C, 0x28, 0x61, 0x47, 0xA2, 0x50, 0x2A,
0x63, 0xF6, 0x21, 0xDE, 0xDA, 0xD8, 0xD5, 0xF0, 0x7F, 0xC5, 0x00, 0x82,
0x70, 0xE6, 0xA3, 0xBF, 0x5C, 0x89, 0x27, 0x4F, 0x51, 0x92, 0x77, 0x03,
0xC3, 0xB0, 0xCC, 0x2E, 0x3B, 0xEC, 0x23, 0xF2, 0x2F, 0x53, 0x41, 0xAF,
0x89, 0x93, 0xFF, 0xD2, 0x80, 0xB1, 0x43, 0x97, 0xDE, 0xD6, 0x19, 0xA0,
0x92, 0x12, 0x7A, 0x3D, 0x66, 0x79, 0xE1, 0xC1, 0xBC, 0xE1, 0x77, 0x70,
0xA2, 0x8B, 0x3D, 0x46, 0x84, 0x53, 0x3F, 0xE4, 0x4E, 0x42, 0x41, 0x37,
0x92, 0x1E, 0x1F, 0xFD, 0x38, 0xB3, 0xF7, 0xEF, 0x87, 0x39, 0x80, 0xD3,
0x56, 0xCF, 0xF4, 0xE0, 0x13, 0xDE, 0x64, 0xB0, 0x72, 0xA4, 0x03, 0x84,
0xC4, 0x41, 0xED, 0x6F, 0xFA, 0x3E, 0xE2, 0xCA, 0x04, 0x20, 0xD2, 0xD7,
0xDC, 0x2C, 0x82, 0x2B, 0x7A, 0xE2, 0x6D, 0xA1, 0x1C, 0x48, 0xDB, 0xCF,
0x89, 0x4F, 0x34, 0x97, 0x3D, 0x28, 0xA8, 0x53, 0xDA, 0xE7, 0xC1, 0xE1,
0x73, 0x15, 0xA3, 0x30, 0x76, 0x7F, 0x8F, 0x23, 0x42, 0x14, 0x3D, 0x51,
0x34, 0xD2, 0x5A, 0xAD, 0x3C, 0x9B, 0xCB, 0xC8, 0xFE, 0x7F, 0x6E, 0x8E,
0x40, 0xF3, 0xBD, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x66, 0x30, 0x64,
0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
0x14, 0xC5, 0x01, 0xAD, 0x7C, 0xE6, 0x63, 0xC9, 0x9C, 0x17, 0x5F, 0xC5,
0xA2, 0xA7, 0xE1, 0x50, 0x5F, 0xE8, 0xF5, 0xA8, 0xC6, 0x30, 0x1D, 0x06,
0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xC5, 0x01, 0xAD, 0x7C,
0xE6, 0x63, 0xC9, 0x9C, 0x17, 0x5F, 0xC5, 0xA2, 0xA7, 0xE1, 0x50, 0x5F,
0xE8, 0xF5, 0xA8, 0xC6, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01,
0x01, 0xFF, 0x04, 0x02, 0x30, 0x00, 0x30, 0x14, 0x06, 0x03, 0x55, 0x1D,
0x11, 0x04, 0x0D, 0x30, 0x0B, 0x82, 0x09, 0x6C, 0x6F, 0x63, 0x61, 0x6C,
0x68, 0x6F, 0x73, 0x74, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
0x71, 0xB3, 0x5D, 0x21, 0xC2, 0x0E, 0xD7, 0xD0, 0xC6, 0xF8, 0x4A, 0x73,
0x87, 0x4D, 0x22, 0x02, 0x27, 0xD0, 0xC7, 0xF8, 0xFD, 0x1A, 0x6D, 0x62,
0x58, 0x82, 0x08, 0x76, 0x20, 0x07, 0xC0, 0x48, 0x92, 0xF3, 0xE9, 0x98,
0x5A, 0xEB, 0x0D, 0x4E, 0x56, 0x95, 0x63, 0x68, 0x4D, 0xAB, 0xD4, 0x00,
0x76, 0xE0, 0x37, 0xCF, 0x0B, 0x11, 0x61, 0x59, 0x5C, 0xDE, 0xF6, 0xA5,
0x14, 0x59, 0xD9, 0x25, 0x9F, 0x59, 0xD9, 0xD3, 0x5E, 0x86, 0xAC, 0x1D,
0xA6, 0x2C, 0x32, 0x42, 0x19, 0x32, 0x13, 0x40, 0x0B, 0x54, 0xCD, 0x67,
0x26, 0xB6, 0xBD, 0xB4, 0x96, 0xA4, 0xCA, 0x1F, 0x7F, 0x37, 0xD6, 0xA8,
0x75, 0xEB, 0x3A, 0x81, 0x51, 0x30, 0xB9, 0xF9, 0x4A, 0x01, 0x6F, 0xD1,
0xD6, 0xED, 0x4F, 0xDF, 0x3F, 0x30, 0x60, 0x06, 0x67, 0x92, 0x8E, 0x61,
0x85, 0x5F, 0x1A, 0xB5, 0x8C, 0xB3, 0x0F, 0x61, 0xA9, 0xFA, 0xDF, 0x5D,
0xC4, 0x64, 0x00, 0xEA, 0x87, 0xB1, 0x33, 0x5F, 0x7D, 0xCB, 0xA3, 0x85,
0x24, 0x6E, 0x2C, 0x65, 0x3B, 0xEA, 0x73, 0x3F, 0x86, 0xD3, 0xFD, 0xE8,
0xE4, 0x02, 0xC6, 0x61, 0x6A, 0x26, 0x17, 0x52, 0x01, 0x25, 0x5C, 0x7F,
0xA8, 0xCE, 0x69, 0x1F, 0xAC, 0x61, 0x2C, 0xB7, 0x04, 0xAF, 0xFD, 0xA4,
0x7A, 0x99, 0xCB, 0x26, 0x15, 0x4C, 0xFF, 0x74, 0xD4, 0x73, 0x0C, 0x57,
0x0C, 0x26, 0xEB, 0xD7, 0x2A, 0xDC, 0x5C, 0xC3, 0x41, 0xBB, 0xC2, 0xF3,
0xCE, 0x16, 0xBD, 0x8E, 0x7B, 0xFB, 0xE9, 0xDF, 0xAB, 0x21, 0x0D, 0x91,
0xB3, 0x8D, 0xD8, 0xCF, 0xC8, 0xF4, 0x49, 0xB9, 0xD0, 0xE3, 0x16, 0x70,
0x3F, 0xB3, 0xDE, 0xD4, 0x07, 0x25, 0xFA, 0x46, 0x44, 0x52, 0x89, 0x4D,
0x89, 0xC8, 0xE2, 0xCA, 0xB5, 0x33, 0x7F, 0xC7, 0x21, 0xBD, 0x28, 0xEF,
0xFE, 0x66, 0x74, 0x03
};
static const unsigned char CERT1[] = {
0x30, 0x82, 0x03, 0x34, 0x30, 0x82, 0x02, 0x1C, 0xA0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x14, 0x70, 0x0F, 0x60, 0xEE, 0xF0, 0x07, 0x9A, 0x9C, 0x69,
0xAC, 0x97, 0x62, 0x26, 0x4F, 0x5D, 0x05, 0xB6, 0xF9, 0x8F, 0x48, 0x30,
0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
0x05, 0x00, 0x30, 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55,
0x04, 0x03, 0x13, 0x04, 0x52, 0x6F, 0x6F, 0x74, 0x30, 0x1E, 0x17, 0x0D,
0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x5A, 0x17, 0x0D, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35,
0x39, 0x35, 0x39, 0x5A, 0x30, 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06,
0x03, 0x55, 0x04, 0x03, 0x13, 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D,
0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01,
0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01,
0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB3, 0xE8, 0x6B, 0xAF, 0x9C, 0x16,
0x52, 0xE3, 0x81, 0x0C, 0x50, 0xAB, 0x25, 0xCE, 0xCC, 0x0D, 0xC7, 0xF2,
0x1F, 0x7F, 0x50, 0xDF, 0x2C, 0x5C, 0x35, 0xD6, 0x62, 0x2E, 0x63, 0x27,
0x41, 0xA7, 0xE4, 0x53, 0xA8, 0x4B, 0x27, 0xFA, 0x13, 0x91, 0xA3, 0xFA,
0x09, 0x4A, 0x2F, 0x3B, 0x5E, 0xCF, 0x77, 0xB3, 0x8A, 0xC1, 0xCD, 0x49,
0x95, 0x9C, 0x75, 0x0D, 0x64, 0x74, 0xEF, 0xE4, 0xD7, 0x4B, 0xB9, 0xA1,
0x9B, 0x68, 0xD2, 0x30, 0x71, 0x48, 0xEA, 0xF7, 0x4B, 0x14, 0xDF, 0x3F,
0x47, 0xA9, 0xD8, 0xBB, 0xEC, 0x8F, 0x28, 0xCC, 0xFA, 0xDF, 0xB4, 0x1F,
0x94, 0x7C, 0x96, 0xFC, 0x08, 0x05, 0x28, 0xF9, 0xE8, 0xF4, 0x2F, 0x2F,
0xEE, 0x62, 0x9C, 0x8A, 0x3A, 0xE0, 0x85, 0x58, 0x60, 0xB6, 0x0F, 0x2D,
0x30, 0xB4, 0xC0, 0x41, 0x54, 0x91, 0x4C, 0x1F, 0x5F, 0xAD, 0xF1, 0x19,
0xF0, 0xC0, 0x22, 0xA6, 0x7D, 0xD8, 0x3F, 0x79, 0x34, 0x59, 0x42, 0x7B,
0x5B, 0xB5, 0x41, 0xC4, 0x64, 0x7F, 0x52, 0xCF, 0x3C, 0x37, 0x22, 0xA1,
0x2F, 0x79, 0x25, 0x94, 0x24, 0x41, 0xC2, 0x3F, 0xFA, 0xC7, 0x75, 0xFB,
0x48, 0xB5, 0x0D, 0x18, 0xA7, 0xF4, 0x54, 0xF3, 0x2E, 0x6E, 0xD8, 0x43,
0x58, 0xC4, 0xAB, 0x50, 0xE8, 0x05, 0xAD, 0x91, 0xB6, 0x1E, 0x01, 0x75,
0xB3, 0x54, 0x9C, 0xDE, 0xA0, 0x99, 0x15, 0xFB, 0xAC, 0xF1, 0x5C, 0x97,
0x49, 0x51, 0xCC, 0xEF, 0x58, 0x12, 0x6F, 0x73, 0x6B, 0xB3, 0x34, 0x14,
0x01, 0x0F, 0x5A, 0x9D, 0xFA, 0xAA, 0xD6, 0x93, 0xD3, 0xE2, 0xEA, 0xC3,
0xAB, 0xBC, 0x4E, 0xED, 0xCC, 0x51, 0xA1, 0xB8, 0xF8, 0x94, 0xB6, 0xB4,
0x2C, 0xA8, 0x86, 0x2B, 0x1F, 0xF6, 0x51, 0x43, 0x29, 0x52, 0x5E, 0x13,
0x89, 0xB3, 0x6A, 0x78, 0x60, 0x4E, 0x4E, 0xC0, 0x1B, 0xA5, 0x02, 0x03,
0x01, 0x00, 0x01, 0xA3, 0x63, 0x30, 0x61, 0x30, 0x1F, 0x06, 0x03, 0x55,
0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xC3, 0x0A, 0xBC, 0xB4,
0x90, 0x63, 0x96, 0x92, 0x45, 0xBC, 0x27, 0xA0, 0xF0, 0x58, 0x89, 0x2A,
0xD5, 0x78, 0x00, 0x12, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04,
0x16, 0x04, 0x14, 0x7C, 0xCF, 0xA3, 0xC6, 0x29, 0xF7, 0xF3, 0xC5, 0xAA,
0x19, 0xD0, 0xC0, 0x16, 0xEB, 0xE0, 0x40, 0x0F, 0xCE, 0x44, 0xA7, 0x30,
0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03,
0x02, 0x00, 0x86, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01,
0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09,
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03,
0x82, 0x01, 0x01, 0x00, 0x54, 0x3B, 0xF4, 0xEA, 0xC6, 0xE4, 0xE8, 0xC0,
0x5B, 0x12, 0xB2, 0xAD, 0xFA, 0xBD, 0xA9, 0xF4, 0x62, 0x03, 0xAD, 0x57,
0x4C, 0x6F, 0x07, 0xA7, 0x47, 0x35, 0x75, 0x3E, 0x48, 0xA2, 0x5B, 0x71,
0x10, 0x01, 0x8F, 0x93, 0x99, 0x9D, 0xA7, 0x47, 0xE3, 0x8E, 0x3E, 0xAF,
0x2D, 0xBA, 0x06, 0xFE, 0xD4, 0xE4, 0x97, 0xBC, 0x10, 0x8D, 0xA6, 0xA5,
0x3A, 0x3C, 0xE6, 0x21, 0xCB, 0x3B, 0xDA, 0x13, 0xE3, 0x4A, 0x23, 0xEB,
0xBC, 0xBA, 0xA5, 0x90, 0x91, 0xAD, 0x55, 0x6E, 0xD5, 0xDD, 0x85, 0x4B,
0x6B, 0x27, 0xD2, 0x39, 0x76, 0x06, 0x2E, 0xD4, 0x23, 0x5B, 0xBB, 0x55,
0xB5, 0x49, 0x3F, 0x7D, 0x2F, 0x21, 0xCB, 0x96, 0x75, 0x19, 0x99, 0xA9,
0x99, 0xF1, 0x0B, 0xBB, 0x3E, 0xC7, 0x10, 0xA7, 0x8B, 0x7A, 0x52, 0xB9,
0x49, 0xE4, 0x14, 0x08, 0x78, 0xE7, 0x3D, 0xD9, 0x98, 0x57, 0xDA, 0xFF,
0xDA, 0xB9, 0x8D, 0x66, 0x75, 0x80, 0xB5, 0x5D, 0xB9, 0xDF, 0x69, 0x65,
0xDB, 0x16, 0xE7, 0x1E, 0xC4, 0x40, 0xE4, 0x46, 0x8A, 0x1E, 0x76, 0x32,
0x16, 0xE7, 0x83, 0x67, 0xDA, 0x78, 0x56, 0xAB, 0x0F, 0x4C, 0x5C, 0xF1,
0x70, 0xDA, 0x66, 0x20, 0xF4, 0xF8, 0x0F, 0xF6, 0xDC, 0x2F, 0x72, 0x97,
0x6B, 0x78, 0x40, 0x79, 0x9D, 0x5B, 0x6D, 0xBE, 0x03, 0xCE, 0x70, 0x42,
0xA8, 0x2A, 0x71, 0x11, 0xDF, 0x2E, 0x81, 0x01, 0xEA, 0x86, 0x12, 0x91,
0x4F, 0xD0, 0x18, 0xED, 0x84, 0xA4, 0x48, 0x30, 0xB9, 0xB9, 0x7B, 0x56,
0x3E, 0xEF, 0x8D, 0xE1, 0x1F, 0xFD, 0x90, 0xB2, 0x44, 0x85, 0x58, 0x6F,
0xA7, 0x30, 0x74, 0x7C, 0xF1, 0xAE, 0x8C, 0x99, 0x3F, 0xF1, 0x4D, 0x57,
0xC5, 0x95, 0x68, 0xC2, 0x36, 0xB2, 0xEC, 0xC2, 0x68, 0x7A, 0xC0, 0x81,
0xA9, 0x55, 0x05, 0xE7, 0xCF, 0xAF, 0x50, 0xAC
};
static const br_x509_certificate CHAIN[] = {
{ (unsigned char *)CERT0, sizeof CERT0 },
{ (unsigned char *)CERT1, sizeof CERT1 }
};
#define CHAIN_LEN 2

View File

@ -0,0 +1,380 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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 <stdint.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "bearssl.h"
/*
* Connect to the specified host and port. The connected socket is
* returned, or -1 on error.
*/
static int
host_connect(const char *host, const char *port)
{
struct addrinfo hints, *si, *p;
int fd;
int err;
memset(&hints, 0, sizeof hints);
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(host, port, &hints, &si);
if (err != 0) {
fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
gai_strerror(err));
return -1;
}
fd = -1;
for (p = si; p != NULL; p = p->ai_next) {
struct sockaddr *sa;
void *addr;
char tmp[INET6_ADDRSTRLEN + 50];
sa = (struct sockaddr *)p->ai_addr;
if (sa->sa_family == AF_INET) {
addr = &((struct sockaddr_in *)sa)->sin_addr;
} else if (sa->sa_family == AF_INET6) {
addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
} else {
addr = NULL;
}
if (addr != NULL) {
inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
} else {
sprintf(tmp, "<unknown family: %d>",
(int)sa->sa_family);
}
fprintf(stderr, "connecting to: %s\n", tmp);
fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (fd < 0) {
perror("socket()");
continue;
}
if (connect(fd, p->ai_addr, p->ai_addrlen) < 0) {
perror("connect()");
close(fd);
continue;
}
break;
}
if (p == NULL) {
freeaddrinfo(si);
fprintf(stderr, "ERROR: failed to connect\n");
return -1;
}
freeaddrinfo(si);
fprintf(stderr, "connected.\n");
return fd;
}
/*
* Low-level data read callback for the simplified SSL I/O API.
*/
static int
sock_read(void *ctx, unsigned char *buf, size_t len)
{
for (;;) {
ssize_t rlen;
rlen = read(*(int *)ctx, buf, len);
if (rlen <= 0) {
if (rlen < 0 && errno == EINTR) {
continue;
}
return -1;
}
return (int)rlen;
}
}
/*
* Low-level data write callback for the simplified SSL I/O API.
*/
static int
sock_write(void *ctx, const unsigned char *buf, size_t len)
{
for (;;) {
ssize_t wlen;
wlen = write(*(int *)ctx, buf, len);
if (wlen <= 0) {
if (wlen < 0 && errno == EINTR) {
continue;
}
return -1;
}
return (int)wlen;
}
}
/*
* The hardcoded trust anchors. These are the two DN + public key that
* correspond to the self-signed certificates cert-root-rsa.pem and
* cert-root-ec.pem.
*
* C code for hardcoded trust anchors can be generated with the "brssl"
* command-line tool (with the "ta" command).
*/
static const unsigned char TA0_DN[] = {
0x30, 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03,
0x13, 0x04, 0x52, 0x6F, 0x6F, 0x74
};
static const unsigned char TA0_RSA_N[] = {
0xB6, 0xD9, 0x34, 0xD4, 0x50, 0xFD, 0xB3, 0xAF, 0x7A, 0x73, 0xF1, 0xCE,
0x38, 0xBF, 0x5D, 0x6F, 0x45, 0xE1, 0xFD, 0x4E, 0xB1, 0x98, 0xC6, 0x60,
0x83, 0x26, 0xD2, 0x17, 0xD1, 0xC5, 0xB7, 0x9A, 0xA3, 0xC1, 0xDE, 0x63,
0x39, 0x97, 0x9C, 0xF0, 0x5E, 0x5C, 0xC8, 0x1C, 0x17, 0xB9, 0x88, 0x19,
0x6D, 0xF0, 0xB6, 0x2E, 0x30, 0x50, 0xA1, 0x54, 0x6E, 0x93, 0xC0, 0xDB,
0xCF, 0x30, 0xCB, 0x9F, 0x1E, 0x27, 0x79, 0xF1, 0xC3, 0x99, 0x52, 0x35,
0xAA, 0x3D, 0xB6, 0xDF, 0xB0, 0xAD, 0x7C, 0xCB, 0x49, 0xCD, 0xC0, 0xED,
0xE7, 0x66, 0x10, 0x2A, 0xE9, 0xCE, 0x28, 0x1F, 0x21, 0x50, 0xFA, 0x77,
0x4C, 0x2D, 0xDA, 0xEF, 0x3C, 0x58, 0xEB, 0x4E, 0xBF, 0xCE, 0xE9, 0xFB,
0x1A, 0xDA, 0xA3, 0x83, 0xA3, 0xCD, 0xA3, 0xCA, 0x93, 0x80, 0xDC, 0xDA,
0xF3, 0x17, 0xCC, 0x7A, 0xAB, 0x33, 0x80, 0x9C, 0xB2, 0xD4, 0x7F, 0x46,
0x3F, 0xC5, 0x3C, 0xDC, 0x61, 0x94, 0xB7, 0x27, 0x29, 0x6E, 0x2A, 0xBC,
0x5B, 0x09, 0x36, 0xD4, 0xC6, 0x3B, 0x0D, 0xEB, 0xBE, 0xCE, 0xDB, 0x1D,
0x1C, 0xBC, 0x10, 0x6A, 0x71, 0x71, 0xB3, 0xF2, 0xCA, 0x28, 0x9A, 0x77,
0xF2, 0x8A, 0xEC, 0x42, 0xEF, 0xB1, 0x4A, 0x8E, 0xE2, 0xF2, 0x1A, 0x32,
0x2A, 0xCD, 0xC0, 0xA6, 0x46, 0x2C, 0x9A, 0xC2, 0x85, 0x37, 0x91, 0x7F,
0x46, 0xA1, 0x93, 0x81, 0xA1, 0x74, 0x66, 0xDF, 0xBA, 0xB3, 0x39, 0x20,
0x91, 0x93, 0xFA, 0x1D, 0xA1, 0xA8, 0x85, 0xE7, 0xE4, 0xF9, 0x07, 0xF6,
0x10, 0xF6, 0xA8, 0x27, 0x01, 0xB6, 0x7F, 0x12, 0xC3, 0x40, 0xC3, 0xC9,
0xE2, 0xB0, 0xAB, 0x49, 0x18, 0x3A, 0x64, 0xB6, 0x59, 0xB7, 0x95, 0xB5,
0x96, 0x36, 0xDF, 0x22, 0x69, 0xAA, 0x72, 0x6A, 0x54, 0x4E, 0x27, 0x29,
0xA3, 0x0E, 0x97, 0x15
};
static const unsigned char TA0_RSA_E[] = {
0x01, 0x00, 0x01
};
static const unsigned char TA1_DN[] = {
0x30, 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03,
0x13, 0x04, 0x52, 0x6F, 0x6F, 0x74
};
static const unsigned char TA1_EC_Q[] = {
0x04, 0x71, 0x74, 0xBA, 0xAB, 0xB9, 0x30, 0x2E, 0x81, 0xD5, 0xE5, 0x57,
0xF9, 0xF3, 0x20, 0x68, 0x0C, 0x9C, 0xF9, 0x64, 0xDB, 0xB4, 0x20, 0x0D,
0x6D, 0xEA, 0x40, 0xD0, 0x4A, 0x6E, 0x42, 0xFD, 0xB6, 0x9A, 0x68, 0x25,
0x44, 0xF6, 0xDF, 0x7B, 0xC4, 0xFC, 0xDE, 0xDD, 0x7B, 0xBB, 0xC5, 0xDB,
0x7C, 0x76, 0x3F, 0x41, 0x66, 0x40, 0x6E, 0xDB, 0xA7, 0x87, 0xC2, 0xE5,
0xD8, 0xC5, 0xF3, 0x7F, 0x8D
};
static const br_x509_trust_anchor TAs[2] = {
{
{ (unsigned char *)TA0_DN, sizeof TA0_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ .rsa = {
(unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N,
(unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E,
} }
}
},
{
{ (unsigned char *)TA1_DN, sizeof TA1_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_EC,
{ .ec = {
BR_EC_secp256r1,
(unsigned char *)TA1_EC_Q, sizeof TA1_EC_Q,
} }
}
}
};
#define TAs_NUM 2
/*
* Main program: this is a simple program that expects 2 or 3 arguments.
* The first two arguments are a hostname and a port; the program will
* open a SSL connection with that server and port. It will then send
* a simple HTTP GET request, using the third argument as target path
* ("/" is used as path if no third argument was provided). The HTTP
* response, complete with header and contents, is received and written
* on stdout.
*/
int
main(int argc, char *argv[])
{
const char *host, *port, *path;
int fd;
br_ssl_client_context sc;
br_x509_minimal_context xc;
unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
br_sslio_context ioc;
/*
* Parse command-line argument: host, port, and path. The path
* is optional; if absent, "/" is used.
*/
if (argc < 3 || argc > 4) {
return EXIT_FAILURE;
}
host = argv[1];
port = argv[2];
if (argc == 4) {
path = argv[3];
} else {
path = "/";
}
/*
* Ignore SIGPIPE to avoid crashing in case of abrupt socket close.
*/
signal(SIGPIPE, SIG_IGN);
/*
* Open the socket to the target server.
*/
fd = host_connect(host, port);
if (fd < 0) {
return EXIT_FAILURE;
}
/*
* Initialise the client context:
* -- Use the "full" profile (all supported algorithms).
* -- The provided X.509 validation engine is initialised, with
* the hardcoded trust anchor.
*/
br_ssl_client_init_full(&sc, &xc, TAs, TAs_NUM);
/*
* Set the I/O buffer to the provided array. We allocated a
* buffer large enough for full-duplex behaviour with all
* allowed sizes of SSL records, hence we set the last argument
* to 1 (which means "split the buffer into separate input and
* output areas").
*/
br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);
/*
* Reset the client context, for a new handshake. We provide the
* target host name: it will be used for the SNI extension. The
* last parameter is 0: we are not trying to resume a session.
*/
br_ssl_client_reset(&sc, host, 0);
/*
* Initialise the simplified I/O wrapper context, to use our
* SSL client context, and the two callbacks for socket I/O.
*/
br_sslio_init(&ioc, &sc.eng, sock_read, &fd, sock_write, &fd);
/*
* Note that while the context has, at that point, already
* assembled the ClientHello to send, nothing happened on the
* network yet. Real I/O will occur only with the next call.
*
* We write our simple HTTP request. We could test each call
* for an error (-1), but this is not strictly necessary, since
* the error state "sticks": if the context fails for any reason
* (e.g. bad server certificate), then it will remain in failed
* state and all subsequent calls will return -1 as well.
*/
br_sslio_write_all(&ioc, "GET ", 4);
br_sslio_write_all(&ioc, path, strlen(path));
br_sslio_write_all(&ioc, " HTTP/1.0\r\nHost: ", 17);
br_sslio_write_all(&ioc, host, strlen(host));
br_sslio_write_all(&ioc, "\r\n\r\n", 4);
/*
* SSL is a buffered protocol: we make sure that all our request
* bytes are sent onto the wire.
*/
br_sslio_flush(&ioc);
/*
* Read the server's response. We use here a small 512-byte buffer,
* but most of the buffering occurs in the client context: the
* server will send full records (up to 16384 bytes worth of data
* each), and the client context buffers one full record at a time.
*/
for (;;) {
int rlen;
unsigned char tmp[512];
rlen = br_sslio_read(&ioc, tmp, sizeof tmp);
if (rlen < 0) {
break;
}
fwrite(tmp, 1, rlen, stdout);
}
/*
* Close the socket.
*/
close(fd);
/*
* Check whether we closed properly or not. If the engine is
* closed, then its error status allows to distinguish between
* a normal closure and a SSL error.
*
* If the engine is NOT closed, then this means that the
* underlying network socket was closed or failed in some way.
* Note that many Web servers out there do not properly close
* their SSL connections (they don't send a close_notify alert),
* which will be reported here as "socket closed without proper
* SSL termination".
*/
if (br_ssl_engine_current_state(&sc.eng) == BR_SSL_CLOSED) {
int err;
err = br_ssl_engine_last_error(&sc.eng);
if (err == 0) {
fprintf(stderr, "closed.\n");
return EXIT_SUCCESS;
} else {
fprintf(stderr, "SSL error %d\n", err);
return EXIT_FAILURE;
}
} else {
fprintf(stderr,
"socket closed without proper SSL termination\n");
return EXIT_FAILURE;
}
}

View File

@ -0,0 +1,601 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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 "bearssl.h"
/*
* A "profile" is an initialisation function for a SSL context, that
* configures a list of cipher suites and algorithm implementations.
* While BearSSL comes with a few predefined profiles, you might one
* to define you own, using the example below as guidance.
*
* Each individual initialisation call sets a parameter or an algorithm
* support. Setting a specific algorithm pulls in the implementation of
* that algorithm in the compiled binary, as per static linking
* behaviour. Removing some of this calls will then reduce total code
* footprint, but also mechanically prevents some features to be
* supported (protocol versions and cipher suites).
*
* The two below define profiles for the client and the server contexts,
* respectively. Of course, in a typical size-constrained application,
* you would use one or the other, not both, to avoid pulling in code
* for both.
*/
void
example_client_profile(br_ssl_client_context *cc
/* and possibly some other arguments */)
{
/*
* A list of cipher suites, by preference (first is most
* preferred). The list below contains all cipher suites supported
* by BearSSL; trim it done to your needs.
*/
static const uint16_t suites[] = {
BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
BR_TLS_RSA_WITH_AES_128_CBC_SHA,
BR_TLS_RSA_WITH_AES_256_CBC_SHA,
BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
};
/*
* Client context must be cleared at some point. This sets
* every value and pointer to 0 or NULL.
*/
br_ssl_client_zero(cc);
/*
* Define minimum and maximum protocol versions. Supported
* versions are:
* BR_TLS10 TLS 1.0
* BR_TLS11 TLS 1.1
* BR_TLS12 TLS 1.2
*/
br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
/*
* Set the PRF implementation(s).
* For TLS 1.0 and 1.1, the "prf10" is needed.
* For TLS 1.2, this depends on the cipher suite:
* -- cipher suites with a name ending in "SHA384" need "prf_sha384";
* -- all others need "prf_sha256".
*
* Note that a cipher suite like TLS_RSA_WITH_AES_128_CBC_SHA will
* use SHA-1 for the per-record MAC (that's what the final "SHA"
* means), but still SHA-256 for the PRF when selected along with
* the TLS-1.2 protocol version.
*/
br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
/*
* Set hash functions for the engine. Required hash functions
* depend on the protocol and cipher suite:
*
* -- TLS 1.0 and 1.1 require both MD5 and SHA-1.
* -- With TLS 1.2, cipher suites with a name ending in "SHA384"
* require SHA-384.
* -- With TLS 1.2, cipher suites with a name ending in "SHA256"
* require SHA-256.
* -- With TLS 1.2, cipher suites with a name ending in "SHA"
* require both SHA-256 and SHA-1.
*
* Moreover, these hash functions are also used to compute
* hashes supporting signatures on the server side (for ECDHE_*
* cipher suites), and on the client side (for client
* certificates, except in the case of full static ECDH). In TLS
* 1.0 and 1.1, SHA-1 (and also MD5) will be used, but with TLS
* 1.2 these hash functions are negotiated between client and
* server; SHA-256 and/or SHA-384 should be sufficient in
* practice.
*
* Note that with current implementations, SHA-224 and SHA-256
* share the same file, so if you use one, you may have the other
* one with no additional overhead. Similarly, SHA-384 and SHA-512
* share the same implementation code.
*/
br_ssl_engine_set_hash(&cc->eng, br_md5_ID, &br_md5_vtable);
br_ssl_engine_set_hash(&cc->eng, br_sha1_ID, &br_sha1_vtable);
br_ssl_engine_set_hash(&cc->eng, br_sha224_ID, &br_sha224_vtable);
br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
br_ssl_engine_set_hash(&cc->eng, br_sha384_ID, &br_sha384_vtable);
br_ssl_engine_set_hash(&cc->eng, br_sha512_ID, &br_sha512_vtable);
/*
* Set the cipher suites. All specified cipher suite MUST be
* supported, and the relevant algorithms MUST have been
* configured (failure to provide needed implementations may
* trigger unwanted behaviours like segfaults or overflows).
*/
br_ssl_engine_set_suites(&cc->eng, suites,
(sizeof suites) / (sizeof suites[0]));
/*
* Public-key algorithm implementations.
*
* -- RSA public core ("rsapub") is needed for "RSA" key exchange
* (cipher suites whose name starts with TLS_RSA).
*
* -- RSA signature verification ("rsavrfy") is needed for
* "ECDHE_RSA" cipher suites (not ECDH_RSA).
*
* -- Elliptic curve implementation ("ec") is needed for cipher
* suites that use elliptic curves (both "ECDH" and "ECDHE"
* cipher suites).
*
* -- ECDSA signature verification is needed for "ECDHE_ECDSA"
* cipher suites (but not for ECDHE_RSA, ECDH_ECDSA or ECDH_RSA).
*
* Normally, you use the "default" implementations, obtained
* through relevant function calls. These functions return
* implementations that are deemed "best" for the current
* platform, where "best" means "fastest within constant-time
* implementations". Selecting the default implementation is a
* mixture of compile-time and runtime checks.
*
* Nevertheless, specific implementations may be selected
* explicitly, e.g. to use code which is slower but with a
* smaller footprint.
*
* The RSA code comes in three variants, called "i15", "i31" and
* "i32". The "i31" code is somewhat faster than the "i32" code.
* Usually, "i31" is faster than "i15", except on some specific
* architectures (ARM Cortex M0, M0+, M1 and M3) where the "i15"
* should be preferred (the "i15" code is constant-time, while
* the "i31" is not, and the "i15" code is faster anyway).
*
* ECDSA code also comes in "i15" and "i31" variants. As in the
* case of RSA, the "i31" code is faster, except on the small
* ARM Cortex M, where the "i15" code is faster and safer.
*
* There are no less than 10 elliptic curve implementations:
*
* - ec_c25519_i15, ec_c25519_i31, ec_c25519_m15 and ec_c25519_m31
* implement Curve25519.
*
* - ec_p256_m15 and ec_p256_m31 implement NIST curve P-256.
*
* - ec_prime_i15 and ec_prime_i31 implement NIST curves P-256,
* P-384 and P-521.
*
* - ec_all_m15 is an aggregate implementation that uses
* ec_c25519_m15, ec_p256_m15 and ec_prime_i15.
*
* - ec_all_m31 is an aggregate implementation that uses
* ec_c25519_m31, ec_p256_m31 and ec_prime_i31.
*
* For a given curve, "m15" is faster than "i15" (but possibly
* with a larger code footprint) and "m31" is faster than "i31"
* (there again with a larger code footprint). For best
* performance, use ec_all_m31, except on the small ARM Cortex M
* where ec_all_m15 should be used. Referencing the other
* implementations directly will result in smaller code, but
* support for fewer curves and possibly lower performance.
*/
br_ssl_client_set_default_rsapub(cc);
br_ssl_engine_set_default_rsavrfy(&cc->eng);
br_ssl_engine_set_default_ecdsa(&cc->eng);
/* Alternate: set implementations explicitly.
br_ssl_client_set_rsapub(cc, &br_rsa_i31_public);
br_ssl_client_set_rsavrfy(cc, &br_rsa_i31_pkcs1_vrfy);
br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m31);
br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i31_vrfy_asn1);
*/
/*
* Record handler:
* -- Cipher suites in AES_128_CBC, AES_256_CBC and 3DES_EDE_CBC
* need the CBC record handler ("set_cbc").
* -- Cipher suites in AES_128_GCM and AES_256_GCM need the GCM
* record handler ("set_gcm").
* -- Cipher suites in CHACHA20_POLY1305 need the ChaCha20+Poly1305
* record handler ("set_chapol").
*/
br_ssl_engine_set_cbc(&cc->eng,
&br_sslrec_in_cbc_vtable,
&br_sslrec_out_cbc_vtable);
br_ssl_engine_set_gcm(&cc->eng,
&br_sslrec_in_gcm_vtable,
&br_sslrec_out_gcm_vtable);
br_ssl_engine_set_chapol(&cc->eng,
&br_sslrec_in_chapol_vtable,
&br_sslrec_out_chapol_vtable);
/*
* Symmetric encryption:
* -- AES_128_CBC and AES_256_CBC require an "aes_cbc" implementation
* (actually two implementations, for encryption and decryption).
* -- 3DES_EDE_CBC requires a "des_cbc" implementation
* (actually two implementations, for encryption and decryption).
* -- AES_128_GCM and AES_256_GCM require an "aes_ctr" imeplementation
* and also a GHASH implementation.
*
* Two 3DES implementations are provided:
*
* des_tab Classical table-based implementation; it is
* not constant-time.
*
* dest_ct Constant-time DES/3DES implementation. It is
* slower than des_tab.
*
* Four AES implementations are provided:
*
* aes_ct Constant-time AES implementation, for 32-bit
* systems.
*
* aes_ct64 Constant-time AES implementation, for 64-bit
* systems. It actually also runs on 32-bit systems,
* but, on such systems, it yields larger code and
* slightly worse performance. On 64-bit systems,
* aes_ct64 is about twice faster than aes_ct for
* CTR processing (GCM encryption and decryption),
* and for CBC (decryption only).
*
* aes_small Smallest implementation provided, but also the
* slowest, and it is not constant-time. Use it
* only if desperate for code size.
*
* aes_big Classical table-based AES implementation. This
* is decently fast and still resonably compact,
* but it is not constant-time.
*
* aes_x86ni Very fast implementation that uses the AES-NI
* opcodes on recent x86 CPU. But it may not be
* compiled in the library if the compiler or
* architecture is not supported; and the CPU
* may also not support the opcodes. Selection
* functions are provided to test for availability
* of the code and the opcodes.
*
* Whether having constant-time implementations is absolutely
* required for security depends on the context (in particular
* whether the target architecture actually has cache memory),
* and while side-channel analysis for non-constant-time AES
* code has been demonstrated in lab conditions, it certainly
* does not apply to all actual usages, and it has never been
* spotted in the wild. It is still considered cautious to use
* constant-time code by default, and to consider the other
* implementations only if duly measured performance issues make
* it mandatory.
*/
br_ssl_engine_set_aes_cbc(&cc->eng,
&br_aes_ct_cbcenc_vtable,
&br_aes_ct_cbcdec_vtable);
br_ssl_engine_set_aes_ctr(&cc->eng,
&br_aes_ct_ctr_vtable);
/* Alternate: aes_ct64
br_ssl_engine_set_aes_cbc(&cc->eng,
&br_aes_ct64_cbcenc_vtable,
&br_aes_ct64_cbcdec_vtable);
br_ssl_engine_set_aes_ctr(&cc->eng,
&br_aes_ct64_ctr_vtable);
*/
/* Alternate: aes_small
br_ssl_engine_set_aes_cbc(&cc->eng,
&br_aes_small_cbcenc_vtable,
&br_aes_small_cbcdec_vtable);
br_ssl_engine_set_aes_ctr(&cc->eng,
&br_aes_small_ctr_vtable);
*/
/* Alternate: aes_big
br_ssl_engine_set_aes_cbc(&cc->eng,
&br_aes_big_cbcenc_vtable,
&br_aes_big_cbcdec_vtable);
br_ssl_engine_set_aes_ctr(&cc->eng,
&br_aes_big_ctr_vtable);
*/
br_ssl_engine_set_des_cbc(&cc->eng,
&br_des_ct_cbcenc_vtable,
&br_des_ct_cbcdec_vtable);
/* Alternate: des_tab
br_ssl_engine_set_des_cbc(&cc->eng,
&br_des_tab_cbcenc_vtable,
&br_des_tab_cbcdec_vtable);
*/
/*
* GHASH is needed for AES_128_GCM and AES_256_GCM. Three
* implementations are provided:
*
* ctmul Uses 32-bit multiplications with a 64-bit result.
*
* ctmul32 Uses 32-bit multiplications with a 32-bit result.
*
* ctmul64 Uses 64-bit multiplications with a 64-bit result.
*
* On 64-bit platforms, ctmul64 is the smallest and fastest of
* the three. On 32-bit systems, ctmul should be preferred. The
* ctmul32 implementation is meant to be used for the specific
* 32-bit systems that do not have a 32x32->64 multiplier (i.e.
* the ARM Cortex-M0 and Cortex-M0+).
*
* These implementations are all constant-time as long as the
* underlying multiplication opcode is constant-time (which is
* true for all modern systems, but not for older architectures
* such that ARM9 or 80486).
*/
br_ssl_engine_set_ghash(&cc->eng,
&br_ghash_ctmul);
/* Alternate: ghash_ctmul32
br_ssl_engine_set_ghash(&cc->eng,
&br_ghash_ctmul32);
*/
/* Alternate: ghash_ctmul64
br_ssl_engine_set_ghash(&cc->eng,
&br_ghash_ctmul64);
*/
#if 0
/*
* For a client, the normal case is to validate the server
* certificate with regards to a set of trust anchors. This
* entails using a br_x509_minimal_context structure, configured
* with the relevant algorithms, as shown below.
*
* Alternatively, the client could "know" the intended server
* public key through an out-of-band mechanism, in which case
* a br_x509_knownkey_context is appropriate, for a much reduced
* code footprint.
*
* We assume here that the following extra parameters have been
* provided:
*
* xc engine context (br_x509_minimal_context *)
* trust_anchors trust anchors (br_x509_trust_anchor *)
* trust_anchors_num number of trust anchors (size_t)
*/
/*
* The X.509 engine needs a hash function for processing the
* subject and issuer DN of certificates and trust anchors. Any
* supported hash function is appropriate; here we use SHA-256.
* The trust an
*/
br_x509_minimal_init(xc, &br_sha256_vtable,
trust_anchors, trust_anchors_num);
/*
* Set suites and asymmetric crypto implementations. We use the
* "i31" code for RSA (it is somewhat faster than the "i32"
* implementation). These implementations are used for
* signature verification on certificates, but not for the
* SSL-specific usage of the server's public key. For instance,
* if the server has an EC public key but the rest of the chain
* (intermediate CA, root...) use RSA, then you would need only
* the RSA verification function below.
*/
br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy);
br_x509_minimal_set_ecdsa(xc,
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
/*
* Set supported hash functions. These are for signatures on
* certificates. There again, you only need the hash functions
* that are actually used in certificates, but if a given
* function was included for the SSL engine, you may as well
* add it here.
*
* Note: the engine explicitly rejects signatures that use MD5.
* Thus, there is no need for MD5 here.
*/
br_ssl_engine_set_hash(xc, br_sha1_ID, &br_sha1_vtable);
br_ssl_engine_set_hash(xc, br_sha224_ID, &br_sha224_vtable);
br_ssl_engine_set_hash(xc, br_sha256_ID, &br_sha256_vtable);
br_ssl_engine_set_hash(xc, br_sha384_ID, &br_sha384_vtable);
br_ssl_engine_set_hash(xc, br_sha512_ID, &br_sha512_vtable);
/*
* Link the X.509 engine in the SSL engine.
*/
br_ssl_engine_set_x509(&cc->eng, &xc->vtable);
#endif
}
/*
* Example server profile. Most of it is shared with the client
* profile, so see the comments in the client function for details.
*
* This example function assumes a server with a (unique) RSA private
* key, so the list of cipher suites is trimmed down for RSA.
*/
void
example_server_profile(br_ssl_server_context *cc,
const br_x509_certificate *chain, size_t chain_len,
const br_rsa_private_key *sk)
{
static const uint16_t suites[] = {
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
BR_TLS_RSA_WITH_AES_128_CBC_SHA,
BR_TLS_RSA_WITH_AES_256_CBC_SHA,
BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
};
br_ssl_server_zero(cc);
br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
/*
* Apart from the requirements listed in the client side, these
* hash functions are also used by the server to compute its
* signature on ECDHE parameters. Which functions are needed
* depends on what the client may support; furthermore, the
* client may fail to send the relevant extension, in which
* case the server will default to whatever it can (as per the
* standard, it should be SHA-1 in that case).
*/
br_ssl_engine_set_hash(&cc->eng, br_md5_ID, &br_md5_vtable);
br_ssl_engine_set_hash(&cc->eng, br_sha1_ID, &br_sha1_vtable);
br_ssl_engine_set_hash(&cc->eng, br_sha224_ID, &br_sha224_vtable);
br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
br_ssl_engine_set_hash(&cc->eng, br_sha384_ID, &br_sha384_vtable);
br_ssl_engine_set_hash(&cc->eng, br_sha512_ID, &br_sha512_vtable);
br_ssl_engine_set_suites(&cc->eng, suites,
(sizeof suites) / (sizeof suites[0]));
/*
* Elliptic curve implementation is used for ECDHE suites (but
* not for ECDH).
*/
br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
/*
* Set the "server policy": handler for the certificate chain
* and private key operations. Here, we indicate that the RSA
* private key is fit for both signing and decrypting, and we
* provide the two relevant implementations.
* BR_KEYTYPE_KEYX allows TLS_RSA_*, BR_KEYTYPE_SIGN allows
* TLS_ECDHE_RSA_*.
*/
br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
br_rsa_i31_private, br_rsa_i31_pkcs1_sign);
/*
* If the server used an EC private key, this call would look
* like this:
br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
cert_issuer_key_type,
&br_ec_prime_i31, br_ecdsa_i31_sign_asn1);
* Note the tricky points:
*
* -- "ECDH" cipher suites use only the EC code (&br_ec_prime_i31);
* the ECDHE_ECDSA cipher suites need both the EC code and
* the ECDSA signature implementation.
*
* -- For "ECDH" (not "ECDHE") cipher suites, the engine must
* know the key type (RSA or EC) for the intermediate CA that
* issued the server's certificate; this is an artefact of
* how the protocol is defined. BearSSL won't try to decode
* the server's certificate to obtain that information (it
* could do that, the code is there, but it would increase the
* footprint). So this must be provided by the caller.
*
* -- BR_KEYTYPE_KEYX allows ECDH, BR_KEYTYPE_SIGN allows
* ECDHE_ECDSA.
*/
br_ssl_engine_set_cbc(&cc->eng,
&br_sslrec_in_cbc_vtable,
&br_sslrec_out_cbc_vtable);
br_ssl_engine_set_gcm(&cc->eng,
&br_sslrec_in_gcm_vtable,
&br_sslrec_out_gcm_vtable);
br_ssl_engine_set_aes_cbc(&cc->eng,
&br_aes_ct_cbcenc_vtable,
&br_aes_ct_cbcdec_vtable);
br_ssl_engine_set_aes_ctr(&cc->eng,
&br_aes_ct_ctr_vtable);
/* Alternate: aes_ct64
br_ssl_engine_set_aes_cbc(&cc->eng,
&br_aes_ct64_cbcenc_vtable,
&br_aes_ct64_cbcdec_vtable);
br_ssl_engine_set_aes_ctr(&cc->eng,
&br_aes_ct64_ctr_vtable);
*/
/* Alternate: aes_small
br_ssl_engine_set_aes_cbc(&cc->eng,
&br_aes_small_cbcenc_vtable,
&br_aes_small_cbcdec_vtable);
br_ssl_engine_set_aes_ctr(&cc->eng,
&br_aes_small_ctr_vtable);
*/
/* Alternate: aes_big
br_ssl_engine_set_aes_cbc(&cc->eng,
&br_aes_big_cbcenc_vtable,
&br_aes_big_cbcdec_vtable);
br_ssl_engine_set_aes_ctr(&cc->eng,
&br_aes_big_ctr_vtable);
*/
br_ssl_engine_set_des_cbc(&cc->eng,
&br_des_ct_cbcenc_vtable,
&br_des_ct_cbcdec_vtable);
/* Alternate: des_tab
br_ssl_engine_set_des_cbc(&cc->eng,
&br_des_tab_cbcenc_vtable,
&br_des_tab_cbcdec_vtable);
*/
br_ssl_engine_set_ghash(&cc->eng,
&br_ghash_ctmul);
/* Alternate: ghash_ctmul32
br_ssl_engine_set_ghash(&cc->eng,
&br_ghash_ctmul32);
*/
/* Alternate: ghash_ctmul64
br_ssl_engine_set_ghash(&cc->eng,
&br_ghash_ctmul64);
*/
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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 "bearssl.h"
/*
* The private key for the server certificate (EC).
*/
static const unsigned char EC_X[] = {
0x03, 0x91, 0x5B, 0x42, 0x06, 0x90, 0x73, 0x91, 0x1B, 0x48, 0xEF, 0x08,
0xFB, 0xB5, 0xAD, 0x75, 0x65, 0xF9, 0xE6, 0xF7, 0x21, 0x47, 0x62, 0x48,
0xFA, 0x3F, 0x97, 0x7B, 0x70, 0x9D, 0x86, 0xA5
};
static const br_ec_private_key EC = {
23,
(unsigned char *)EC_X, sizeof EC_X
};

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIAORW0IGkHORG0jvCPu1rXVl+eb3IUdiSPo/l3twnYaloAoGCCqGSM49AwEHoUQDQgAE
Xzidp/9Niq/2NDlGGvw63/Qjqqnq+8UI3gCOvnmlN1hMbd0ByqtH34m2xxcfOPwdIBTdRcDgj5NO
OAv86ZmhSQ==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,23 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1HodJ7orOmeykWr754NEyu0cda3dTYNi1qpolbIkIXsVriqZaBXtZvC4WOfT
9S7G2Spe5w4u5/xnWcDIYX1LpG/dn9nIhYdkx7oaDynUlqh4mmtiIKky0O6pjChhR6JQKmP2Id7a
2NXwf8UAgnDmo79ciSdPUZJ3A8OwzC477CPyL1NBr4mT/9KAsUOX3tYZoJISej1meeHBvOF3cKKL
PUaEUz/kTkJBN5IeH/04s/fvhzmA01bP9OAT3mSwcqQDhMRB7W/6PuLKBCDS19wsgit64m2hHEjb
z4lPNJc9KKhT2ufB4XMVozB2f48jQhQ9UTTSWq08m8vI/n9ujkDzvQIDAQABAoIBADzb40jzQpl+
hT+wsIl96HDlXI76Z1Zh6SgKdF1YQpASdMHHstwE19Rx46OXd3cVWGBwifFNdzL8cU/cb6i43jcx
0X2NQCm6/6tTi05HkXw7shus4VTwkb0VdxvNnxuJCsQxkJjf/7g3AyVdtIkoNG+3ipZAW7BGLu+1
mAjLv18h4LniI8JGWQK75z8xNQzEdOFVyqC1PujjC5emesxlRW8Ks+MzQ+20WTpHGkLAoLJZJ1XE
bDQqFbkRXu4imKLtA4iyBrEpXEKZR85tVO+NQOGdPyH/ugK23nSDcJlI2PTHSlGABTpZZUmigO4O
b8lppU7cFa2JemKG3kEj0BWDOWMCgYEA+fYynFHXcbJi7YEk2vapLMMtVZSVUeU2Ep4uH47YIiJk
XqP8YPAU3BBIb08afcw3Iyd2tjGq3nDJ7KsKUPHqeXl0vjurLmOXom8KRXvXbNJtG3AxA68miyjF
+ElnRUHx0zUFJyp5IdoGtj2i6DxA+m/E/PXEBeuaMapAfl7uIlsCgYEA2Zwa3JRR9sGW2g4RPzco
ejOwxL7faCvTHGVnejyvWVCrKTYXORVxl2LdzSXujf8mj3Ehvo+chU464STH4Urf0GCzxEQurHMW
XwfJOnNe2pvu4rSpPTMUe+6n1Kz3U+Y+8IVXTIuWG93XNvyJN1l1lnWLLvcELSmJ2befcTvi7ccC
gYEA5PwCLyvWRwTZFaRaI/EU17nRHPYpuEVXPMUFkclk/BgvhHeLay5knZiZEscPiLB8zkqHuK5V
TsNaZ+HkaHTFjRSTuvWkgrGfpqE8cpzZo4o9g4ZKkIpyr8bhXOu5nDumEgsfNlr1bupxfZ+HTmJs
UD/14JowQhAsSFUkEeBbHMMCgYEAjazgoDPAmVK4kAcQm4Ohys3UjINomD3QGHC8ygywbQnkJdSd
kgCwD8vCdEn54mD4DfOt8I83bGLeWq7Do55H0TbkUyfA622SZxR+optyagmToe3VMY8MCxP6GLDz
5Z/F4notuBw5ArOP5rDL9Uk9EVQ95bnU8kJVCXZPTD2dJQkCgYByDKfPBpVp9HUgNAPgz5pRk/VC
LvKFvs5POLWMoplC871lOOI0PyGd9b2zv3M8GN728H+hwlXyOOkOHjHn21HFcY1ncTqfVVJg7kX2
CJiBt3sv8pZ9c9Cmq6qDSUE1qZBnztO5c1SqhACIiJAdhpvluM6JChtHYjHCP8OMhgk8hg==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIEJOkvo4MZ9N+wlTodEzmWor1RauybudPe92K15viDbzoAoGCCqGSM49AwEHoUQDQgAE
cC6SggEXbG2r4dFjCUhJ0qY1UtM8c7uyiDeYh/GN4Oxlmg4T9e2RYci2bTOEbq6OVYDNSZ4Hv9Cu
nebQsycWoQ==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,23 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAs+hrr5wWUuOBDFCrJc7MDcfyH39Q3yxcNdZiLmMnQafkU6hLJ/oTkaP6CUov
O17Pd7OKwc1JlZx1DWR07+TXS7mhm2jSMHFI6vdLFN8/R6nYu+yPKMz637QflHyW/AgFKPno9C8v
7mKcijrghVhgtg8tMLTAQVSRTB9frfEZ8MAipn3YP3k0WUJ7W7VBxGR/Us88NyKhL3kllCRBwj/6
x3X7SLUNGKf0VPMubthDWMSrUOgFrZG2HgF1s1Sc3qCZFfus8VyXSVHM71gSb3NrszQUAQ9anfqq
1pPT4urDq7xO7cxRobj4lLa0LKiGKx/2UUMpUl4TibNqeGBOTsAbpQIDAQABAoIBAAtBpQ85SGpK
QsZG+9ZjQIAyPPN8j05PY7uYnM8DNC8W9qHHW2B2dKf9pwTSx+7CiV+Xc7yZgBukzOwYF3r1CgV6
aWKkZdZTGDlfXKrDJx3wQhfL/s8SODYr+nfbbcT6KXx9WnaAx1J2iA3cDjU5qN9rRqwP+yF7TZYC
NoXXGoTmHb7gj1H1IJNdiUgG0netXpM2HydRLzwHDweKav6sm4V4TTeHPYokVp8W7lL7xRhwQXVD
lcE1noY5NczXV88k9n0EbqGDwX3pJoDC/xWzBFh/+oupxotM4KY2dKJGmtKTmiIef3u43CPv5SYh
V2OcEXn+joV5qHGhg6yN+ri0/ucCgYEA4x2NBFNtbpx3lmc2r2hwfbawcTVKKlxqJWdoG2bd7HQz
bO+uqtxhLOxEou4S9uPUVylvpNlDs3xQ+DF9p8oTo5XlHvA6DT/cAjWSQ+MRHqCV30T0lDSd0McZ
4PaV1nq94bGuPVrGe/Dex5dL+VVhn2tpoqwudsyx5hHA8hFE1zcCgYEAysnhrQa1HZQ0hOaA2c/e
A8I47dEIyGi4N6uJVBUMM1ecKifs4FKybOtI+XM3mwuAXUyVQGi2SZBBpE4bN3oUDWGwYF7SAJV0
JJHpBxlZBvYRC7Vfh8HFPYIQCynP0Q4BeQVDaCPW3puJsTWnn2lNhT/PsSm3v76JwTRrBoqaGgMC
gYAwyyiAxWu9V+BZb9NP3CBO4fEGYWyNrU0gvBahzHfhVRW3Ucc07iPygtA8MOniIRB9qWlTAVqK
NSswJ3HXmpKdkpanDvVp405hKyFBdIc5DUclsKrbLHK7aAsnSdLnQXeKBaJpjBcYiadTOi4YYz+W
AH2xdUyGOXP++dF6MDuaAQKBgQCtWyHygW5pR94R0t9J1FpuCiYSn4ULlgINjTXLzGZuqbGVlCX6
qpdfZ1At92IMyCtHFwXsVtemUYzcAe1gYpsryVw3Njf+ScVM0fNMn02tFsQBp15wNqT/7OT8NhUz
GO8HXwl9yE2SZZKzDDQsoZ+kjqVlRU2QvDkVElN/9xK/swKBgDz6m4XHvhvITo2bd8/i4FxTN1gr
napgAc2DHOzCmeyYCjKvZAJDLeNleni1kj1UfrzVrH2BFM38asRJu8xPI4WjfH1fFktNjXVu6Ctk
YFu0/0TlWkzowZHmE/K0M0tuJLt42m/DLW8deMyl38x+PUPUZb4OdVAKAua/voOMZtQw
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEINx41f6h/utlj52XNFbIGJdkF3qZy1/g9hH2/yV4t/tnoAoGCCqGSM49AwEHoUQDQgAE
cXS6q7kwLoHV5Vf58yBoDJz5ZNu0IA1t6kDQSm5C/baaaCVE9t97xPze3Xu7xdt8dj9BZkBu26eH
wuXYxfN/jQ==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,23 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAttk01FD9s696c/HOOL9db0Xh/U6xmMZggybSF9HFt5qjwd5jOZec8F5cyBwX
uYgZbfC2LjBQoVRuk8DbzzDLnx4nefHDmVI1qj2237CtfMtJzcDt52YQKunOKB8hUPp3TC3a7zxY
606/zun7Gtqjg6PNo8qTgNza8xfMeqszgJyy1H9GP8U83GGUtycpbiq8Wwk21MY7Deu+ztsdHLwQ
anFxs/LKKJp38orsQu+xSo7i8hoyKs3ApkYsmsKFN5F/RqGTgaF0Zt+6szkgkZP6HaGohefk+Qf2
EPaoJwG2fxLDQMPJ4rCrSRg6ZLZZt5W1ljbfImmqcmpUTicpow6XFQIDAQABAoIBAENjavKDBPWn
yygXKqtEb/GWHlNmoNKO7jv33z9TGxzvW8IULZqos3jtNiG0JNRGgiTALcx5FwZWYUiIMBq8v5bd
nKv3O+DyaP/crdzkNxRCsekoXSXGuleugsHLs1IudTA4yDMamSTkCZH/LwH3KYNXJ+9hNhqsiu9D
yqM9HIad2k/hmVFv4NDdH3VWqsQJFfrGEXgKRJKNpuzKeST3oo4iLcwH9NGiKXfjW23ekOiLYFwZ
q8Yd6tOgNLpGuDWk9rlXPJALyXFZ/3UXZaKU5f0ZRfPfMQgM8toeWeWJS0FW7g6aLCJATsfOu/II
j3nTVCPryvGF4mwe/y+Rgbd67xMCgYEA3Wpiac27hvbLzwbSTWYsKql5uKV0HTim3haNDuzMHJVY
ZRJSuTY+rZBoaiuDRKMCMI3dQM8AZUJfHQclyTxjtn17Ig8cTKMN6Wr2MRTBplCq3wNLVjbOPAE2
cv74gUfgpRLdlyueYO7j6PcTS+l41+wB1A/zAEm346Eoxoztt5cCgYEA02ipYQFX4T+8BSkcEyzP
qeMT9d3BLPm4tTeq2sXRgcfEbF/ENcAX9OfPSEx4kVtzsfJXma5/dg0fuVgl1hO5WLBT+L6MJ/A2
sGX3Y7x+doXI0xcNd/Epr7oWqZuCO7477vzJcNtud/KQJj2EmRNaHKKtaohqO5dnNhsM540lnDMC
gYBU40KT2eJ5ngkJeE4Mio2IVa1rE1PvGBcxsmemPzcKBl/7cAjzJU7mcCT3/3K2T+C5CMq43CQE
rmuUz3a3LkX0YytgJXbuEt10jiORMaoEv4yjL7okdaKf8r8TW5mexxXjc9Ys7PYtp6kNWhy1z+8a
qUsSKIM7qwerZ9AgP0usRQKBgQDEHy4y/coG/tdweii/aSzlT/Huf2B8VtaR1yi7eBTaLvb8CwO9
UY1n970GN1sKjiqQhF/cBFPesmIh0bKYHQgvTLU555uiWWiC0LVmYzF2xrn9ij9GbAXeLeZkRg3V
Wq/DD+PYvNiIkhBESYG/eIJ6WjhCwna6/cQUH5gjH4AqnQKBgQCsKyjLtx+FeFu7PZ8AgCGWRVvs
suxB74pxlMqMgBbBHyAGQOTTuaaTr/gwNXAAErAXS1X9VsAcAkM/yFv19mdZmJQG9vUMOe48AZDB
c7xt3t3Ul71eAlbAYkrQGtq64yO3w7ny4C7GUVqMX03XwKToCrXqeKfGwrZGNP+lgZYrbw==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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 "bearssl.h"
/*
* The private key for the server certificate (RSA).
*/
static const unsigned char RSA_P[] = {
0xF9, 0xF6, 0x32, 0x9C, 0x51, 0xD7, 0x71, 0xB2, 0x62, 0xED, 0x81, 0x24,
0xDA, 0xF6, 0xA9, 0x2C, 0xC3, 0x2D, 0x55, 0x94, 0x95, 0x51, 0xE5, 0x36,
0x12, 0x9E, 0x2E, 0x1F, 0x8E, 0xD8, 0x22, 0x22, 0x64, 0x5E, 0xA3, 0xFC,
0x60, 0xF0, 0x14, 0xDC, 0x10, 0x48, 0x6F, 0x4F, 0x1A, 0x7D, 0xCC, 0x37,
0x23, 0x27, 0x76, 0xB6, 0x31, 0xAA, 0xDE, 0x70, 0xC9, 0xEC, 0xAB, 0x0A,
0x50, 0xF1, 0xEA, 0x79, 0x79, 0x74, 0xBE, 0x3B, 0xAB, 0x2E, 0x63, 0x97,
0xA2, 0x6F, 0x0A, 0x45, 0x7B, 0xD7, 0x6C, 0xD2, 0x6D, 0x1B, 0x70, 0x31,
0x03, 0xAF, 0x26, 0x8B, 0x28, 0xC5, 0xF8, 0x49, 0x67, 0x45, 0x41, 0xF1,
0xD3, 0x35, 0x05, 0x27, 0x2A, 0x79, 0x21, 0xDA, 0x06, 0xB6, 0x3D, 0xA2,
0xE8, 0x3C, 0x40, 0xFA, 0x6F, 0xC4, 0xFC, 0xF5, 0xC4, 0x05, 0xEB, 0x9A,
0x31, 0xAA, 0x40, 0x7E, 0x5E, 0xEE, 0x22, 0x5B
};
static const unsigned char RSA_Q[] = {
0xD9, 0x9C, 0x1A, 0xDC, 0x94, 0x51, 0xF6, 0xC1, 0x96, 0xDA, 0x0E, 0x11,
0x3F, 0x37, 0x28, 0x7A, 0x33, 0xB0, 0xC4, 0xBE, 0xDF, 0x68, 0x2B, 0xD3,
0x1C, 0x65, 0x67, 0x7A, 0x3C, 0xAF, 0x59, 0x50, 0xAB, 0x29, 0x36, 0x17,
0x39, 0x15, 0x71, 0x97, 0x62, 0xDD, 0xCD, 0x25, 0xEE, 0x8D, 0xFF, 0x26,
0x8F, 0x71, 0x21, 0xBE, 0x8F, 0x9C, 0x85, 0x4E, 0x3A, 0xE1, 0x24, 0xC7,
0xE1, 0x4A, 0xDF, 0xD0, 0x60, 0xB3, 0xC4, 0x44, 0x2E, 0xAC, 0x73, 0x16,
0x5F, 0x07, 0xC9, 0x3A, 0x73, 0x5E, 0xDA, 0x9B, 0xEE, 0xE2, 0xB4, 0xA9,
0x3D, 0x33, 0x14, 0x7B, 0xEE, 0xA7, 0xD4, 0xAC, 0xF7, 0x53, 0xE6, 0x3E,
0xF0, 0x85, 0x57, 0x4C, 0x8B, 0x96, 0x1B, 0xDD, 0xD7, 0x36, 0xFC, 0x89,
0x37, 0x59, 0x75, 0x96, 0x75, 0x8B, 0x2E, 0xF7, 0x04, 0x2D, 0x29, 0x89,
0xD9, 0xB7, 0x9F, 0x71, 0x3B, 0xE2, 0xED, 0xC7
};
static const unsigned char RSA_DP[] = {
0xE4, 0xFC, 0x02, 0x2F, 0x2B, 0xD6, 0x47, 0x04, 0xD9, 0x15, 0xA4, 0x5A,
0x23, 0xF1, 0x14, 0xD7, 0xB9, 0xD1, 0x1C, 0xF6, 0x29, 0xB8, 0x45, 0x57,
0x3C, 0xC5, 0x05, 0x91, 0xC9, 0x64, 0xFC, 0x18, 0x2F, 0x84, 0x77, 0x8B,
0x6B, 0x2E, 0x64, 0x9D, 0x98, 0x99, 0x12, 0xC7, 0x0F, 0x88, 0xB0, 0x7C,
0xCE, 0x4A, 0x87, 0xB8, 0xAE, 0x55, 0x4E, 0xC3, 0x5A, 0x67, 0xE1, 0xE4,
0x68, 0x74, 0xC5, 0x8D, 0x14, 0x93, 0xBA, 0xF5, 0xA4, 0x82, 0xB1, 0x9F,
0xA6, 0xA1, 0x3C, 0x72, 0x9C, 0xD9, 0xA3, 0x8A, 0x3D, 0x83, 0x86, 0x4A,
0x90, 0x8A, 0x72, 0xAF, 0xC6, 0xE1, 0x5C, 0xEB, 0xB9, 0x9C, 0x3B, 0xA6,
0x12, 0x0B, 0x1F, 0x36, 0x5A, 0xF5, 0x6E, 0xEA, 0x71, 0x7D, 0x9F, 0x87,
0x4E, 0x62, 0x6C, 0x50, 0x3F, 0xF5, 0xE0, 0x9A, 0x30, 0x42, 0x10, 0x2C,
0x48, 0x55, 0x24, 0x11, 0xE0, 0x5B, 0x1C, 0xC3
};
static const unsigned char RSA_DQ[] = {
0x8D, 0xAC, 0xE0, 0xA0, 0x33, 0xC0, 0x99, 0x52, 0xB8, 0x90, 0x07, 0x10,
0x9B, 0x83, 0xA1, 0xCA, 0xCD, 0xD4, 0x8C, 0x83, 0x68, 0x98, 0x3D, 0xD0,
0x18, 0x70, 0xBC, 0xCA, 0x0C, 0xB0, 0x6D, 0x09, 0xE4, 0x25, 0xD4, 0x9D,
0x92, 0x00, 0xB0, 0x0F, 0xCB, 0xC2, 0x74, 0x49, 0xF9, 0xE2, 0x60, 0xF8,
0x0D, 0xF3, 0xAD, 0xF0, 0x8F, 0x37, 0x6C, 0x62, 0xDE, 0x5A, 0xAE, 0xC3,
0xA3, 0x9E, 0x47, 0xD1, 0x36, 0xE4, 0x53, 0x27, 0xC0, 0xEB, 0x6D, 0x92,
0x67, 0x14, 0x7E, 0xA2, 0x9B, 0x72, 0x6A, 0x09, 0x93, 0xA1, 0xED, 0xD5,
0x31, 0x8F, 0x0C, 0x0B, 0x13, 0xFA, 0x18, 0xB0, 0xF3, 0xE5, 0x9F, 0xC5,
0xE2, 0x7A, 0x2D, 0xB8, 0x1C, 0x39, 0x02, 0xB3, 0x8F, 0xE6, 0xB0, 0xCB,
0xF5, 0x49, 0x3D, 0x11, 0x54, 0x3D, 0xE5, 0xB9, 0xD4, 0xF2, 0x42, 0x55,
0x09, 0x76, 0x4F, 0x4C, 0x3D, 0x9D, 0x25, 0x09
};
static const unsigned char RSA_IQ[] = {
0x72, 0x0C, 0xA7, 0xCF, 0x06, 0x95, 0x69, 0xF4, 0x75, 0x20, 0x34, 0x03,
0xE0, 0xCF, 0x9A, 0x51, 0x93, 0xF5, 0x42, 0x2E, 0xF2, 0x85, 0xBE, 0xCE,
0x4F, 0x38, 0xB5, 0x8C, 0xA2, 0x99, 0x42, 0xF3, 0xBD, 0x65, 0x38, 0xE2,
0x34, 0x3F, 0x21, 0x9D, 0xF5, 0xBD, 0xB3, 0xBF, 0x73, 0x3C, 0x18, 0xDE,
0xF6, 0xF0, 0x7F, 0xA1, 0xC2, 0x55, 0xF2, 0x38, 0xE9, 0x0E, 0x1E, 0x31,
0xE7, 0xDB, 0x51, 0xC5, 0x71, 0x8D, 0x67, 0x71, 0x3A, 0x9F, 0x55, 0x52,
0x60, 0xEE, 0x45, 0xF6, 0x08, 0x98, 0x81, 0xB7, 0x7B, 0x2F, 0xF2, 0x96,
0x7D, 0x73, 0xD0, 0xA6, 0xAB, 0xAA, 0x83, 0x49, 0x41, 0x35, 0xA9, 0x90,
0x67, 0xCE, 0xD3, 0xB9, 0x73, 0x54, 0xAA, 0x84, 0x00, 0x88, 0x88, 0x90,
0x1D, 0x86, 0x9B, 0xE5, 0xB8, 0xCE, 0x89, 0x0A, 0x1B, 0x47, 0x62, 0x31,
0xC2, 0x3F, 0xC3, 0x8C, 0x86, 0x09, 0x3C, 0x86
};
static const br_rsa_private_key RSA = {
2048,
(unsigned char *)RSA_P, sizeof RSA_P,
(unsigned char *)RSA_Q, sizeof RSA_Q,
(unsigned char *)RSA_DP, sizeof RSA_DP,
(unsigned char *)RSA_DQ, sizeof RSA_DQ,
(unsigned char *)RSA_IQ, sizeof RSA_IQ
};

View File

@ -0,0 +1,436 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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 <stdint.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "bearssl.h"
/*
* This sample code can use three possible certificate chains:
* -- A full-RSA chain (server key is RSA, certificates are signed with RSA)
* -- A full-EC chain (server key is EC, certificates are signed with ECDSA)
* -- A mixed chain (server key is EC, certificates are signed with RSA)
*
* The macros below define which chain is selected. This impacts the list
* of supported cipher suites.
*
* Other macros, which can be defined (with a non-zero value):
*
* SERVER_PROFILE_MIN_FS
* Select a "minimal" profile with forward security (ECDHE cipher
* suite).
*
* SERVER_PROFILE_MIN_NOFS
* Select a "minimal" profile without forward security (RSA or ECDH
* cipher suite, but not ECDHE).
*
* SERVER_CHACHA20
* If SERVER_PROFILE_MIN_FS is selected, then this macro selects
* a cipher suite with ChaCha20+Poly1305; otherwise, AES/GCM is
* used. This macro has no effect otherwise, since there is no
* non-forward secure cipher suite that uses ChaCha20+Poly1305.
*/
#if !(SERVER_RSA || SERVER_EC || SERVER_MIXED)
#define SERVER_RSA 1
#define SERVER_EC 0
#define SERVER_MIXED 0
#endif
#if SERVER_RSA
#include "chain-rsa.h"
#include "key-rsa.h"
#define SKEY RSA
#elif SERVER_EC
#include "chain-ec.h"
#include "key-ec.h"
#define SKEY EC
#elif SERVER_MIXED
#include "chain-ec+rsa.h"
#include "key-ec.h"
#define SKEY EC
#else
#error Must use one of RSA, EC or MIXED chains.
#endif
/*
* Create a server socket bound to the specified host and port. If 'host'
* is NULL, this will bind "generically" (all addresses).
*
* Returned value is the server socket descriptor, or -1 on error.
*/
static int
host_bind(const char *host, const char *port)
{
struct addrinfo hints, *si, *p;
int fd;
int err;
memset(&hints, 0, sizeof hints);
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(host, port, &hints, &si);
if (err != 0) {
fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
gai_strerror(err));
return -1;
}
fd = -1;
for (p = si; p != NULL; p = p->ai_next) {
struct sockaddr *sa;
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
size_t sa_len;
void *addr;
char tmp[INET6_ADDRSTRLEN + 50];
int opt;
sa = (struct sockaddr *)p->ai_addr;
if (sa->sa_family == AF_INET) {
sa4 = *(struct sockaddr_in *)sa;
sa = (struct sockaddr *)&sa4;
sa_len = sizeof sa4;
addr = &sa4.sin_addr;
if (host == NULL) {
sa4.sin_addr.s_addr = INADDR_ANY;
}
} else if (sa->sa_family == AF_INET6) {
sa6 = *(struct sockaddr_in6 *)sa;
sa = (struct sockaddr *)&sa6;
sa_len = sizeof sa6;
addr = &sa6.sin6_addr;
if (host == NULL) {
sa6.sin6_addr = in6addr_any;
}
} else {
addr = NULL;
sa_len = p->ai_addrlen;
}
if (addr != NULL) {
inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
} else {
sprintf(tmp, "<unknown family: %d>",
(int)sa->sa_family);
}
fprintf(stderr, "binding to: %s\n", tmp);
fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (fd < 0) {
perror("socket()");
continue;
}
opt = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
opt = 0;
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof opt);
if (bind(fd, sa, sa_len) < 0) {
perror("bind()");
close(fd);
continue;
}
break;
}
if (p == NULL) {
freeaddrinfo(si);
fprintf(stderr, "ERROR: failed to bind\n");
return -1;
}
freeaddrinfo(si);
if (listen(fd, 5) < 0) {
perror("listen()");
close(fd);
return -1;
}
fprintf(stderr, "bound.\n");
return fd;
}
/*
* Accept a single client on the provided server socket. This is blocking.
* On error, this returns -1.
*/
static int
accept_client(int server_fd)
{
int fd;
struct sockaddr sa;
socklen_t sa_len;
char tmp[INET6_ADDRSTRLEN + 50];
const char *name;
sa_len = sizeof sa;
fd = accept(server_fd, &sa, &sa_len);
if (fd < 0) {
perror("accept()");
return -1;
}
name = NULL;
switch (sa.sa_family) {
case AF_INET:
name = inet_ntop(AF_INET,
&((struct sockaddr_in *)&sa)->sin_addr,
tmp, sizeof tmp);
break;
case AF_INET6:
name = inet_ntop(AF_INET6,
&((struct sockaddr_in6 *)&sa)->sin6_addr,
tmp, sizeof tmp);
break;
}
if (name == NULL) {
sprintf(tmp, "<unknown: %lu>", (unsigned long)sa.sa_family);
name = tmp;
}
fprintf(stderr, "accepting connection from: %s\n", name);
return fd;
}
/*
* Low-level data read callback for the simplified SSL I/O API.
*/
static int
sock_read(void *ctx, unsigned char *buf, size_t len)
{
for (;;) {
ssize_t rlen;
rlen = read(*(int *)ctx, buf, len);
if (rlen <= 0) {
if (rlen < 0 && errno == EINTR) {
continue;
}
return -1;
}
return (int)rlen;
}
}
/*
* Low-level data write callback for the simplified SSL I/O API.
*/
static int
sock_write(void *ctx, const unsigned char *buf, size_t len)
{
for (;;) {
ssize_t wlen;
wlen = write(*(int *)ctx, buf, len);
if (wlen <= 0) {
if (wlen < 0 && errno == EINTR) {
continue;
}
return -1;
}
return (int)wlen;
}
}
/*
* Sample HTTP response to send.
*/
static const char *HTTP_RES =
"HTTP/1.0 200 OK\r\n"
"Content-Length: 46\r\n"
"Connection: close\r\n"
"Content-Type: text/html; charset=iso-8859-1\r\n"
"\r\n"
"<html>\r\n"
"<body>\r\n"
"<p>Test!</p>\r\n"
"</body>\r\n"
"</html>\r\n";
/*
* Main program: this is a simple program that expects 1 argument: a
* port number. This will start a simple network server on that port,
* that expects incoming SSL clients. It handles only one client at a
* time (handling several would require threads, sub-processes, or
* multiplexing with select()/poll(), all of which being possible).
*
* For each client, the server will wait for two successive newline
* characters (ignoring CR characters, so CR+LF is accepted), then
* produce a sample static HTTP response. This is very crude, but
* sufficient for explanatory purposes.
*/
int
main(int argc, char *argv[])
{
const char *port;
int fd;
if (argc != 2) {
return EXIT_FAILURE;
}
port = argv[1];
/*
* Ignore SIGPIPE to avoid crashing in case of abrupt socket close.
*/
signal(SIGPIPE, SIG_IGN);
/*
* Open the server socket.
*/
fd = host_bind(NULL, port);
if (fd < 0) {
return EXIT_FAILURE;
}
/*
* Process each client, one at a time.
*/
for (;;) {
int cfd;
br_ssl_server_context sc;
unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
br_sslio_context ioc;
int lcwn, err;
cfd = accept_client(fd);
if (cfd < 0) {
return EXIT_FAILURE;
}
/*
* Initialise the context with the cipher suites and
* algorithms. This depends on the server key type
* (and, for EC keys, the signature algorithm used by
* the CA to sign the server's certificate).
*
* Depending on the defined macros, we may select one of
* the "minimal" profiles. Key exchange algorithm depends
* on the key type:
* RSA key: RSA or ECDHE_RSA
* EC key, cert signed with ECDSA: ECDH_ECDSA or ECDHE_ECDSA
* EC key, cert signed with RSA: ECDH_RSA or ECDHE_ECDSA
*/
#if SERVER_RSA
#if SERVER_PROFILE_MIN_FS
#if SERVER_CHACHA20
br_ssl_server_init_mine2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
#else
br_ssl_server_init_mine2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
#endif
#elif SERVER_PROFILE_MIN_NOFS
br_ssl_server_init_minr2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
#else
br_ssl_server_init_full_rsa(&sc, CHAIN, CHAIN_LEN, &SKEY);
#endif
#elif SERVER_EC
#if SERVER_PROFILE_MIN_FS
#if SERVER_CHACHA20
br_ssl_server_init_minf2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
#else
br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
#endif
#elif SERVER_PROFILE_MIN_NOFS
br_ssl_server_init_minv2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
#else
br_ssl_server_init_full_ec(&sc, CHAIN, CHAIN_LEN,
BR_KEYTYPE_EC, &SKEY);
#endif
#else /* SERVER_MIXED */
#if SERVER_PROFILE_MIN_FS
#if SERVER_CHACHA20
br_ssl_server_init_minf2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
#else
br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
#endif
#elif SERVER_PROFILE_MIN_NOFS
br_ssl_server_init_minu2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
#else
br_ssl_server_init_full_ec(&sc, CHAIN, CHAIN_LEN,
BR_KEYTYPE_RSA, &SKEY);
#endif
#endif
/*
* Set the I/O buffer to the provided array. We
* allocated a buffer large enough for full-duplex
* behaviour with all allowed sizes of SSL records,
* hence we set the last argument to 1 (which means
* "split the buffer into separate input and output
* areas").
*/
br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);
/*
* Reset the server context, for a new handshake.
*/
br_ssl_server_reset(&sc);
/*
* Initialise the simplified I/O wrapper context.
*/
br_sslio_init(&ioc, &sc.eng, sock_read, &cfd, sock_write, &cfd);
/*
* Read bytes until two successive LF (or CR+LF) are received.
*/
lcwn = 0;
for (;;) {
unsigned char x;
if (br_sslio_read(&ioc, &x, 1) < 0) {
goto client_drop;
}
if (x == 0x0D) {
continue;
}
if (x == 0x0A) {
if (lcwn) {
break;
}
lcwn = 1;
} else {
lcwn = 0;
}
}
/*
* Write a response and close the connection.
*/
br_sslio_write_all(&ioc, HTTP_RES, strlen(HTTP_RES));
br_sslio_close(&ioc);
client_drop:
err = br_ssl_engine_last_error(&sc.eng);
if (err == 0) {
fprintf(stderr, "SSL closed (correctly).\n");
} else {
fprintf(stderr, "SSL error: %d\n", err);
}
close(cfd);
}
}

View File

@ -0,0 +1,346 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* 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 "inner.h"
/*
* Implementation Notes
* ====================
*
* The combined CTR + CBC-MAC functions can only handle full blocks,
* so some buffering is necessary.
*
* - 'ptr' contains a value from 0 to 15, which is the number of bytes
* accumulated in buf[] that still needs to be processed with the
* current CBC-MAC computation.
*
* - When processing the message itself, CTR encryption/decryption is
* also done at the same time. The first 'ptr' bytes of buf[] then
* contains the plaintext bytes, while the last '16 - ptr' bytes of
* buf[] are the remnants of the stream block, to be used against
* the next input bytes, when available. When 'ptr' is 0, the
* contents of buf[] are to be ignored.
*
* - The current counter and running CBC-MAC values are kept in 'ctr'
* and 'cbcmac', respectively.
*/
/* see bearssl_block.h */
void
br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx)
{
ctx->bctx = bctx;
}
/* see bearssl_block.h */
int
br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len,
uint64_t aad_len, uint64_t data_len, size_t tag_len)
{
unsigned char tmp[16];
unsigned u, q;
if (nonce_len < 7 || nonce_len > 13) {
return 0;
}
if (tag_len < 4 || tag_len > 16 || (tag_len & 1) != 0) {
return 0;
}
q = 15 - (unsigned)nonce_len;
ctx->tag_len = tag_len;
/*
* Block B0, to start CBC-MAC.
*/
tmp[0] = (aad_len > 0 ? 0x40 : 0x00)
| (((unsigned)tag_len - 2) << 2)
| (q - 1);
memcpy(tmp + 1, nonce, nonce_len);
for (u = 0; u < q; u ++) {
tmp[15 - u] = (unsigned char)data_len;
data_len >>= 8;
}
if (data_len != 0) {
/*
* If the data length was not entirely consumed in the
* loop above, then it exceeds the maximum limit of
* q bytes (when encoded).
*/
return 0;
}
/*
* Start CBC-MAC.
*/
memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, tmp, sizeof tmp);
/*
* Assemble AAD length header.
*/
if ((aad_len >> 32) != 0) {
ctx->buf[0] = 0xFF;
ctx->buf[1] = 0xFF;
br_enc64be(ctx->buf + 2, aad_len);
ctx->ptr = 10;
} else if (aad_len >= 0xFF00) {
ctx->buf[0] = 0xFF;
ctx->buf[1] = 0xFE;
br_enc32be(ctx->buf + 2, (uint32_t)aad_len);
ctx->ptr = 6;
} else if (aad_len > 0) {
br_enc16be(ctx->buf, (unsigned)aad_len);
ctx->ptr = 2;
} else {
ctx->ptr = 0;
}
/*
* Make initial counter value and compute tag mask.
*/
ctx->ctr[0] = q - 1;
memcpy(ctx->ctr + 1, nonce, nonce_len);
memset(ctx->ctr + 1 + nonce_len, 0, q);
memset(ctx->tagmask, 0, sizeof ctx->tagmask);
(*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
ctx->tagmask, sizeof ctx->tagmask);
return 1;
}
/* see bearssl_block.h */
void
br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len)
{
const unsigned char *dbuf;
size_t ptr;
dbuf = data;
/*
* Complete partial block, if needed.
*/
ptr = ctx->ptr;
if (ptr != 0) {
size_t clen;
clen = (sizeof ctx->buf) - ptr;
if (clen > len) {
memcpy(ctx->buf + ptr, dbuf, len);
ctx->ptr = ptr + len;
return;
}
memcpy(ctx->buf + ptr, dbuf, clen);
dbuf += clen;
len -= clen;
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
ctx->buf, sizeof ctx->buf);
}
/*
* Process complete blocks.
*/
ptr = len & 15;
len -= ptr;
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, dbuf, len);
dbuf += len;
/*
* Copy last partial block in the context buffer.
*/
memcpy(ctx->buf, dbuf, ptr);
ctx->ptr = ptr;
}
/* see bearssl_block.h */
void
br_ccm_flip(br_ccm_context *ctx)
{
size_t ptr;
/*
* Complete AAD partial block with zeros, if necessary.
*/
ptr = ctx->ptr;
if (ptr != 0) {
memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
ctx->buf, sizeof ctx->buf);
ctx->ptr = 0;
}
/*
* Counter was already set by br_ccm_reset().
*/
}
/* see bearssl_block.h */
void
br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len)
{
unsigned char *dbuf;
size_t ptr;
dbuf = data;
/*
* Complete a partial block, if any: ctx->buf[] contains
* ctx->ptr plaintext bytes (already reported), and the other
* bytes are CTR stream output.
*/
ptr = ctx->ptr;
if (ptr != 0) {
size_t clen;
size_t u;
clen = (sizeof ctx->buf) - ptr;
if (clen > len) {
clen = len;
}
if (encrypt) {
for (u = 0; u < clen; u ++) {
unsigned w, x;
w = ctx->buf[ptr + u];
x = dbuf[u];
ctx->buf[ptr + u] = x;
dbuf[u] = w ^ x;
}
} else {
for (u = 0; u < clen; u ++) {
unsigned w;
w = ctx->buf[ptr + u] ^ dbuf[u];
dbuf[u] = w;
ctx->buf[ptr + u] = w;
}
}
dbuf += clen;
len -= clen;
ptr += clen;
if (ptr < sizeof ctx->buf) {
ctx->ptr = ptr;
return;
}
(*ctx->bctx)->mac(ctx->bctx,
ctx->cbcmac, ctx->buf, sizeof ctx->buf);
}
/*
* Process all complete blocks. Note that the ctrcbc API is for
* encrypt-then-MAC (CBC-MAC is computed over the encrypted
* blocks) while CCM uses MAC-and-encrypt (CBC-MAC is computed
* over the plaintext blocks). Therefore, we need to use the
* _decryption_ function for encryption, and the encryption
* function for decryption (this works because CTR encryption
* and decryption are identical, so the choice really is about
* computing the CBC-MAC before or after XORing with the CTR
* stream).
*/
ptr = len & 15;
len -= ptr;
if (encrypt) {
(*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
dbuf, len);
} else {
(*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
dbuf, len);
}
dbuf += len;
/*
* If there is some remaining data, then we need to compute an
* extra block of CTR stream.
*/
if (ptr != 0) {
size_t u;
memset(ctx->buf, 0, sizeof ctx->buf);
(*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
ctx->buf, sizeof ctx->buf);
if (encrypt) {
for (u = 0; u < ptr; u ++) {
unsigned w, x;
w = ctx->buf[u];
x = dbuf[u];
ctx->buf[u] = x;
dbuf[u] = w ^ x;
}
} else {
for (u = 0; u < ptr; u ++) {
unsigned w;
w = ctx->buf[u] ^ dbuf[u];
dbuf[u] = w;
ctx->buf[u] = w;
}
}
}
ctx->ptr = ptr;
}
/* see bearssl_block.h */
size_t
br_ccm_get_tag(br_ccm_context *ctx, void *tag)
{
size_t ptr;
size_t u;
/*
* If there is some buffered data, then we need to pad it with
* zeros and finish up CBC-MAC.
*/
ptr = ctx->ptr;
if (ptr != 0) {
memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
ctx->buf, sizeof ctx->buf);
}
/*
* XOR the tag mask into the CBC-MAC output.
*/
for (u = 0; u < ctx->tag_len; u ++) {
ctx->cbcmac[u] ^= ctx->tagmask[u];
}
memcpy(tag, ctx->cbcmac, ctx->tag_len);
return ctx->tag_len;
}
/* see bearssl_block.h */
uint32_t
br_ccm_check_tag(br_ccm_context *ctx, const void *tag)
{
unsigned char tmp[16];
size_t u, tag_len;
uint32_t z;
tag_len = br_ccm_get_tag(ctx, tmp);
z = 0;
for (u = 0; u < tag_len; u ++) {
z |= tmp[u] ^ ((const unsigned char *)tag)[u];
}
return EQ0(z);
}

View File

@ -0,0 +1,525 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* 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 "inner.h"
/*
* Implementation Notes
* ====================
*
* The combined CTR + CBC-MAC functions can only handle full blocks,
* so some buffering is necessary. Moreover, EAX has a special padding
* rule for CBC-MAC, which implies that we cannot compute the MAC over
* the last received full block until we know whether we are at the
* end of the data or not.
*
* - 'ptr' contains a value from 1 to 16, which is the number of bytes
* accumulated in buf[] that still needs to be processed with the
* current OMAC computation. Beware that this can go to 16: a
* complete block cannot be processed until it is known whether it
* is the last block or not. However, it can never be 0, because
* OMAC^t works on an input that is at least one-block long.
*
* - When processing the message itself, CTR encryption/decryption is
* also done at the same time. The first 'ptr' bytes of buf[] then
* contains the encrypted bytes, while the last '16 - ptr' bytes of
* buf[] are the remnants of the stream block, to be used against
* the next input bytes, when available.
*
* - The current counter and running CBC-MAC values are kept in 'ctr'
* and 'cbcmac', respectively.
*
* - The derived keys for padding are kept in L2 and L4 (double and
* quadruple of Enc_K(0^n), in GF(2^128), respectively).
*/
/*
* Start an OMAC computation; the first block is the big-endian
* representation of the provided value ('val' must fit on one byte).
* We make it a delayed block because it may also be the last one,
*/
static void
omac_start(br_eax_context *ctx, unsigned val)
{
memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
memset(ctx->buf, 0, sizeof ctx->buf);
ctx->buf[15] = val;
ctx->ptr = 16;
}
/*
* Double a value in finite field GF(2^128), defined with modulus
* X^128+X^7+X^2+X+1.
*/
static void
double_gf128(unsigned char *dst, const unsigned char *src)
{
unsigned cc;
int i;
cc = 0x87 & -((unsigned)src[0] >> 7);
for (i = 15; i >= 0; i --) {
unsigned z;
z = (src[i] << 1) ^ cc;
cc = z >> 8;
dst[i] = (unsigned char)z;
}
}
/*
* Apply padding to the last block, currently in ctx->buf (with
* ctx->ptr bytes), and finalize OMAC computation.
*/
static void
do_pad(br_eax_context *ctx)
{
unsigned char *pad;
size_t ptr, u;
ptr = ctx->ptr;
if (ptr == 16) {
pad = ctx->L2;
} else {
ctx->buf[ptr ++] = 0x80;
memset(ctx->buf + ptr, 0x00, 16 - ptr);
pad = ctx->L4;
}
for (u = 0; u < sizeof ctx->buf; u ++) {
ctx->buf[u] ^= pad[u];
}
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf);
}
/*
* Apply CBC-MAC on the provided data, with buffering management.
*
* Upon entry, two situations are acceptable:
*
* ctx->ptr == 0: there is no data to process in ctx->buf
* ctx->ptr == 16: there is a full block of unprocessed data in ctx->buf
*
* Upon exit, ctx->ptr may be zero only if it was already zero on entry,
* and len == 0. In all other situations, ctx->ptr will be non-zero on
* exit (and may have value 16).
*/
static void
do_cbcmac_chunk(br_eax_context *ctx, const void *data, size_t len)
{
size_t ptr;
if (len == 0) {
return;
}
ptr = len & (size_t)15;
if (ptr == 0) {
len -= 16;
ptr = 16;
} else {
len -= ptr;
}
if (ctx->ptr == 16) {
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
ctx->buf, sizeof ctx->buf);
}
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, data, len);
memcpy(ctx->buf, (const unsigned char *)data + len, ptr);
ctx->ptr = ptr;
}
/* see bearssl_aead.h */
void
br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx)
{
unsigned char tmp[16], iv[16];
ctx->vtable = &br_eax_vtable;
ctx->bctx = bctx;
/*
* Encrypt a whole-zero block to compute L2 and L4.
*/
memset(tmp, 0, sizeof tmp);
memset(iv, 0, sizeof iv);
(*bctx)->ctr(bctx, iv, tmp, sizeof tmp);
double_gf128(ctx->L2, tmp);
double_gf128(ctx->L4, ctx->L2);
}
/* see bearssl_aead.h */
void
br_eax_capture(const br_eax_context *ctx, br_eax_state *st)
{
/*
* We capture the three OMAC* states _after_ processing the
* initial block (assuming that nonce, message and AAD are
* all non-empty).
*/
int i;
memset(st->st, 0, sizeof st->st);
for (i = 0; i < 3; i ++) {
unsigned char tmp[16];
memset(tmp, 0, sizeof tmp);
tmp[15] = (unsigned char)i;
(*ctx->bctx)->mac(ctx->bctx, st->st[i], tmp, sizeof tmp);
}
}
/* see bearssl_aead.h */
void
br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len)
{
/*
* Process nonce with OMAC^0.
*/
omac_start(ctx, 0);
do_cbcmac_chunk(ctx, nonce, len);
do_pad(ctx);
memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
/*
* Start OMAC^1 for the AAD ("header" in the EAX specification).
*/
omac_start(ctx, 1);
/*
* We use ctx->head[0] as temporary flag to mark that we are
* using a "normal" reset().
*/
ctx->head[0] = 0;
}
/* see bearssl_aead.h */
void
br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st,
const void *nonce, size_t len)
{
if (len == 0) {
omac_start(ctx, 0);
} else {
memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
ctx->ptr = 0;
do_cbcmac_chunk(ctx, nonce, len);
}
do_pad(ctx);
memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
memcpy(ctx->cbcmac, st->st[1], sizeof ctx->cbcmac);
ctx->ptr = 0;
memcpy(ctx->ctr, st->st[2], sizeof ctx->ctr);
/*
* We use ctx->head[0] as a flag to indicate that we use a
* a recorded state, with ctx->ctr containing the preprocessed
* first block for OMAC^2.
*/
ctx->head[0] = 1;
}
/* see bearssl_aead.h */
void
br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st,
const void *nonce, size_t len)
{
if (len == 0) {
omac_start(ctx, 0);
} else {
memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
ctx->ptr = 0;
do_cbcmac_chunk(ctx, nonce, len);
}
do_pad(ctx);
memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
memcpy(ctx->head, st->st[1], sizeof ctx->head);
memcpy(ctx->cbcmac, st->st[2], sizeof ctx->cbcmac);
ctx->ptr = 0;
}
/* see bearssl_aead.h */
void
br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len)
{
size_t ptr;
ptr = ctx->ptr;
/*
* If there is a partial block, first complete it.
*/
if (ptr < 16) {
size_t clen;
clen = 16 - ptr;
if (len <= clen) {
memcpy(ctx->buf + ptr, data, len);
ctx->ptr = ptr + len;
return;
}
memcpy(ctx->buf + ptr, data, clen);
data = (const unsigned char *)data + clen;
len -= clen;
}
/*
* We now have a full block in buf[], and this is not the last
* block.
*/
do_cbcmac_chunk(ctx, data, len);
}
/* see bearssl_aead.h */
void
br_eax_flip(br_eax_context *ctx)
{
int from_capture;
/*
* ctx->head[0] may be non-zero if the context was reset with
* a pre-AAD captured state. In that case, ctx->ctr[] contains
* the state for OMAC^2 _after_ processing the first block.
*/
from_capture = ctx->head[0];
/*
* Complete the OMAC computation on the AAD.
*/
do_pad(ctx);
memcpy(ctx->head, ctx->cbcmac, sizeof ctx->cbcmac);
/*
* Start OMAC^2 for the encrypted data.
* If the context was initialized from a captured state, then
* the OMAC^2 value is in the ctr[] array.
*/
if (from_capture) {
memcpy(ctx->cbcmac, ctx->ctr, sizeof ctx->cbcmac);
ctx->ptr = 0;
} else {
omac_start(ctx, 2);
}
/*
* Initial counter value for CTR is the processed nonce.
*/
memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
}
/* see bearssl_aead.h */
void
br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len)
{
unsigned char *dbuf;
size_t ptr;
/*
* Ensure that there is actual data to process.
*/
if (len == 0) {
return;
}
dbuf = data;
ptr = ctx->ptr;
/*
* We may have ptr == 0 here if we initialized from a captured
* state. In that case, there is no partially consumed block
* or unprocessed data.
*/
if (ptr != 0 && ptr != 16) {
/*
* We have a partially consumed block.
*/
size_t u, clen;
clen = 16 - ptr;
if (len <= clen) {
clen = len;
}
if (encrypt) {
for (u = 0; u < clen; u ++) {
ctx->buf[ptr + u] ^= dbuf[u];
}
memcpy(dbuf, ctx->buf + ptr, clen);
} else {
for (u = 0; u < clen; u ++) {
unsigned dx, sx;
sx = ctx->buf[ptr + u];
dx = dbuf[u];
ctx->buf[ptr + u] = dx;
dbuf[u] = sx ^ dx;
}
}
if (len <= clen) {
ctx->ptr = ptr + clen;
return;
}
dbuf += clen;
len -= clen;
}
/*
* We now have a complete encrypted block in buf[] that must still
* be processed with OMAC, and this is not the final buf.
* Exception: when ptr == 0, no block has been produced yet.
*/
if (ptr != 0) {
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
ctx->buf, sizeof ctx->buf);
}
/*
* Do CTR encryption or decryption and CBC-MAC for all full blocks
* except the last.
*/
ptr = len & (size_t)15;
if (ptr == 0) {
len -= 16;
ptr = 16;
} else {
len -= ptr;
}
if (encrypt) {
(*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
dbuf, len);
} else {
(*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
dbuf, len);
}
dbuf += len;
/*
* Compute next block of CTR stream, and use it to finish
* encrypting or decrypting the data.
*/
memset(ctx->buf, 0, sizeof ctx->buf);
(*ctx->bctx)->ctr(ctx->bctx, ctx->ctr, ctx->buf, sizeof ctx->buf);
if (encrypt) {
size_t u;
for (u = 0; u < ptr; u ++) {
ctx->buf[u] ^= dbuf[u];
}
memcpy(dbuf, ctx->buf, ptr);
} else {
size_t u;
for (u = 0; u < ptr; u ++) {
unsigned dx, sx;
sx = ctx->buf[u];
dx = dbuf[u];
ctx->buf[u] = dx;
dbuf[u] = sx ^ dx;
}
}
ctx->ptr = ptr;
}
/*
* Complete tag computation. The final tag is written in ctx->cbcmac.
*/
static void
do_final(br_eax_context *ctx)
{
size_t u;
do_pad(ctx);
/*
* Authentication tag is the XOR of the three OMAC outputs for
* the nonce, AAD and encrypted data.
*/
for (u = 0; u < 16; u ++) {
ctx->cbcmac[u] ^= ctx->nonce[u] ^ ctx->head[u];
}
}
/* see bearssl_aead.h */
void
br_eax_get_tag(br_eax_context *ctx, void *tag)
{
do_final(ctx);
memcpy(tag, ctx->cbcmac, sizeof ctx->cbcmac);
}
/* see bearssl_aead.h */
void
br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len)
{
do_final(ctx);
memcpy(tag, ctx->cbcmac, len);
}
/* see bearssl_aead.h */
uint32_t
br_eax_check_tag_trunc(br_eax_context *ctx, const void *tag, size_t len)
{
unsigned char tmp[16];
size_t u;
int x;
br_eax_get_tag(ctx, tmp);
x = 0;
for (u = 0; u < len; u ++) {
x |= tmp[u] ^ ((const unsigned char *)tag)[u];
}
return EQ0(x);
}
/* see bearssl_aead.h */
uint32_t
br_eax_check_tag(br_eax_context *ctx, const void *tag)
{
return br_eax_check_tag_trunc(ctx, tag, 16);
}
/* see bearssl_aead.h */
const br_aead_class br_eax_vtable = {
16,
(void (*)(const br_aead_class **, const void *, size_t))
&br_eax_reset,
(void (*)(const br_aead_class **, const void *, size_t))
&br_eax_aad_inject,
(void (*)(const br_aead_class **))
&br_eax_flip,
(void (*)(const br_aead_class **, int, void *, size_t))
&br_eax_run,
(void (*)(const br_aead_class **, void *))
&br_eax_get_tag,
(uint32_t (*)(const br_aead_class **, const void *))
&br_eax_check_tag,
(void (*)(const br_aead_class **, void *, size_t))
&br_eax_get_tag_trunc,
(uint32_t (*)(const br_aead_class **, const void *, size_t))
&br_eax_check_tag_trunc
};

View File

@ -0,0 +1,318 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* 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 "inner.h"
/*
* Implementation Notes
* ====================
*
* Since CTR and GHASH implementations can handle only full blocks, a
* 16-byte buffer (buf[]) is maintained in the context:
*
* - When processing AAD, buf[] contains the 0-15 unprocessed bytes.
*
* - When doing CTR encryption / decryption, buf[] contains the AES output
* for the last partial block, to be used with the next few bytes of
* data, as well as the already encrypted bytes. For instance, if the
* processed data length so far is 21 bytes, then buf[0..4] contains
* the five last encrypted bytes, and buf[5..15] contains the next 11
* AES output bytes to be XORed with the next 11 bytes of input.
*
* The recorded AES output bytes are used to complete the block when
* the corresponding bytes are obtained. Note that buf[] always
* contains the _encrypted_ bytes, whether we apply encryption or
* decryption: these bytes are used as input to GHASH when the block
* is complete.
*
* In both cases, the low bits of the data length counters (count_aad,
* count_ctr) are used to work out the current situation.
*/
/* see bearssl_aead.h */
void
br_gcm_init(br_gcm_context *ctx, const br_block_ctr_class **bctx, br_ghash gh)
{
unsigned char iv[12];
ctx->vtable = &br_gcm_vtable;
ctx->bctx = bctx;
ctx->gh = gh;
/*
* The GHASH key h[] is the raw encryption of the all-zero
* block. Since we only have a CTR implementation, we use it
* with an all-zero IV and a zero counter, to CTR-encrypt an
* all-zero block.
*/
memset(ctx->h, 0, sizeof ctx->h);
memset(iv, 0, sizeof iv);
(*bctx)->run(bctx, iv, 0, ctx->h, sizeof ctx->h);
}
/* see bearssl_aead.h */
void
br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len)
{
/*
* If the provided nonce is 12 bytes, then this is the initial
* IV for CTR mode; it will be used with a counter that starts
* at 2 (value 1 is for encrypting the GHASH output into the tag).
*
* If the provided nonce has any other length, then it is hashed
* (with GHASH) into a 16-byte value that will be the IV for CTR
* (both 12-byte IV and 32-bit counter).
*/
if (len == 12) {
memcpy(ctx->j0_1, iv, 12);
ctx->j0_2 = 1;
} else {
unsigned char ty[16], tmp[16];
memset(ty, 0, sizeof ty);
ctx->gh(ty, ctx->h, iv, len);
memset(tmp, 0, 8);
br_enc64be(tmp + 8, (uint64_t)len << 3);
ctx->gh(ty, ctx->h, tmp, 16);
memcpy(ctx->j0_1, ty, 12);
ctx->j0_2 = br_dec32be(ty + 12);
}
ctx->jc = ctx->j0_2 + 1;
memset(ctx->y, 0, sizeof ctx->y);
ctx->count_aad = 0;
ctx->count_ctr = 0;
}
/* see bearssl_aead.h */
void
br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len)
{
size_t ptr, dlen;
ptr = (size_t)ctx->count_aad & (size_t)15;
if (ptr != 0) {
/*
* If there is a partial block, then we first try to
* complete it.
*/
size_t clen;
clen = 16 - ptr;
if (len < clen) {
memcpy(ctx->buf + ptr, data, len);
ctx->count_aad += (uint64_t)len;
return;
}
memcpy(ctx->buf + ptr, data, clen);
ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
data = (const unsigned char *)data + clen;
len -= clen;
ctx->count_aad += (uint64_t)clen;
}
/*
* Now AAD is aligned on a 16-byte block (with regards to GHASH).
* We process all complete blocks, and save the last partial
* block.
*/
dlen = len & ~(size_t)15;
ctx->gh(ctx->y, ctx->h, data, dlen);
memcpy(ctx->buf, (const unsigned char *)data + dlen, len - dlen);
ctx->count_aad += (uint64_t)len;
}
/* see bearssl_aead.h */
void
br_gcm_flip(br_gcm_context *ctx)
{
/*
* We complete the GHASH computation if there is a partial block.
* The GHASH implementation automatically applies padding with
* zeros.
*/
size_t ptr;
ptr = (size_t)ctx->count_aad & (size_t)15;
if (ptr != 0) {
ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
}
}
/* see bearssl_aead.h */
void
br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len)
{
unsigned char *buf;
size_t ptr, dlen;
buf = data;
ptr = (size_t)ctx->count_ctr & (size_t)15;
if (ptr != 0) {
/*
* If we have a partial block, then we try to complete it.
*/
size_t u, clen;
clen = 16 - ptr;
if (len < clen) {
clen = len;
}
for (u = 0; u < clen; u ++) {
unsigned x, y;
x = buf[u];
y = x ^ ctx->buf[ptr + u];
ctx->buf[ptr + u] = encrypt ? y : x;
buf[u] = y;
}
ctx->count_ctr += (uint64_t)clen;
buf += clen;
len -= clen;
if (ptr + clen < 16) {
return;
}
ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
}
/*
* Process full blocks.
*/
dlen = len & ~(size_t)15;
if (!encrypt) {
ctx->gh(ctx->y, ctx->h, buf, dlen);
}
ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->jc, buf, dlen);
if (encrypt) {
ctx->gh(ctx->y, ctx->h, buf, dlen);
}
buf += dlen;
len -= dlen;
ctx->count_ctr += (uint64_t)dlen;
if (len > 0) {
/*
* There is a partial block.
*/
size_t u;
memset(ctx->buf, 0, sizeof ctx->buf);
ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1,
ctx->jc, ctx->buf, 16);
for (u = 0; u < len; u ++) {
unsigned x, y;
x = buf[u];
y = x ^ ctx->buf[u];
ctx->buf[u] = encrypt ? y : x;
buf[u] = y;
}
ctx->count_ctr += (uint64_t)len;
}
}
/* see bearssl_aead.h */
void
br_gcm_get_tag(br_gcm_context *ctx, void *tag)
{
size_t ptr;
unsigned char tmp[16];
ptr = (size_t)ctx->count_ctr & (size_t)15;
if (ptr > 0) {
/*
* There is a partial block: encrypted/decrypted data has
* been produced, but the encrypted bytes must still be
* processed by GHASH.
*/
ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
}
/*
* Final block for GHASH: the AAD and plaintext lengths (in bits).
*/
br_enc64be(tmp, ctx->count_aad << 3);
br_enc64be(tmp + 8, ctx->count_ctr << 3);
ctx->gh(ctx->y, ctx->h, tmp, 16);
/*
* Tag is the GHASH output XORed with the encryption of the
* nonce with the initial counter value.
*/
memcpy(tag, ctx->y, 16);
(*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->j0_2, tag, 16);
}
/* see bearssl_aead.h */
void
br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len)
{
unsigned char tmp[16];
br_gcm_get_tag(ctx, tmp);
memcpy(tag, tmp, len);
}
/* see bearssl_aead.h */
uint32_t
br_gcm_check_tag_trunc(br_gcm_context *ctx, const void *tag, size_t len)
{
unsigned char tmp[16];
size_t u;
int x;
br_gcm_get_tag(ctx, tmp);
x = 0;
for (u = 0; u < len; u ++) {
x |= tmp[u] ^ ((const unsigned char *)tag)[u];
}
return EQ0(x);
}
/* see bearssl_aead.h */
uint32_t
br_gcm_check_tag(br_gcm_context *ctx, const void *tag)
{
return br_gcm_check_tag_trunc(ctx, tag, 16);
}
/* see bearssl_aead.h */
const br_aead_class br_gcm_vtable = {
16,
(void (*)(const br_aead_class **, const void *, size_t))
&br_gcm_reset,
(void (*)(const br_aead_class **, const void *, size_t))
&br_gcm_aad_inject,
(void (*)(const br_aead_class **))
&br_gcm_flip,
(void (*)(const br_aead_class **, int, void *, size_t))
&br_gcm_run,
(void (*)(const br_aead_class **, void *))
&br_gcm_get_tag,
(uint32_t (*)(const br_aead_class **, const void *))
&br_gcm_check_tag,
(void (*)(const br_aead_class **, void *, size_t))
&br_gcm_get_tag_trunc,
(uint32_t (*)(const br_aead_class **, const void *, size_t))
&br_gcm_check_tag_trunc
};

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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 "inner.h"
/* see inner.h */
void
br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len)
{
unsigned char *d;
const unsigned char *s;
d = dst;
s = src;
while (len -- > 0) {
uint32_t x, y;
x = *s ++;
y = *d;
*d = MUX(ctl, x, y);
d ++;
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* 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 "inner.h"
/* see inner.h */
void
br_range_dec16be(uint16_t *v, size_t num, const void *src)
{
const unsigned char *buf;
buf = src;
while (num -- > 0) {
*v ++ = br_dec16be(buf);
buf += 2;
}
}

Some files were not shown because too many files have changed in this diff Show More