1769b514d0
Disabled by default, used by loader and sbin/veriexec Reviewed by: emaste Sponsored by: Juniper Networks Differential Revision: D16334
573 lines
17 KiB
C
573 lines
17 KiB
C
/*
|
|
* 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 BRSSL_H__
|
|
#define BRSSL_H__
|
|
|
|
#ifndef _STANDALONE
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
#elif !defined(STAND_H)
|
|
#include <stand.h>
|
|
#endif
|
|
|
|
#include "bearssl.h"
|
|
|
|
/*
|
|
* malloc() wrapper:
|
|
* -- If len is 0, then NULL is returned.
|
|
* -- If len is non-zero, and allocation fails, then an error message is
|
|
* printed and the process exits with an error code.
|
|
*/
|
|
void *xmalloc(size_t len);
|
|
|
|
/*
|
|
* free() wrapper, meant to release blocks allocated with xmalloc().
|
|
*/
|
|
void xfree(void *buf);
|
|
|
|
/*
|
|
* Duplicate a character string into a newly allocated block.
|
|
*/
|
|
char *xstrdup(const void *src);
|
|
|
|
/*
|
|
* Allocate a new block with the provided length, filled with a copy
|
|
* of exactly that many bytes starting at address 'src'.
|
|
*/
|
|
void *xblobdup(const void *src, size_t len);
|
|
|
|
/*
|
|
* Duplicate a public key, into newly allocated blocks. The returned
|
|
* key must be later on released with xfreepkey().
|
|
*/
|
|
br_x509_pkey *xpkeydup(const br_x509_pkey *pk);
|
|
|
|
/*
|
|
* Release a public key that was allocated with xpkeydup(). If pk is NULL,
|
|
* this function does nothing.
|
|
*/
|
|
void xfreepkey(br_x509_pkey *pk);
|
|
|
|
/*
|
|
* Macros for growable arrays.
|
|
*/
|
|
|
|
/*
|
|
* Make a structure type for a vector of 'type'.
|
|
*/
|
|
#define VECTOR(type) struct { \
|
|
type *buf; \
|
|
size_t ptr, len; \
|
|
}
|
|
|
|
/*
|
|
* Constant initialiser for a vector.
|
|
*/
|
|
#define VEC_INIT { 0, 0, 0 }
|
|
|
|
/*
|
|
* Clear a vector.
|
|
*/
|
|
#define VEC_CLEAR(vec) do { \
|
|
xfree((vec).buf); \
|
|
(vec).buf = NULL; \
|
|
(vec).ptr = 0; \
|
|
(vec).len = 0; \
|
|
} while (0)
|
|
|
|
/*
|
|
* Clear a vector, first calling the provided function on each vector
|
|
* element.
|
|
*/
|
|
#define VEC_CLEAREXT(vec, fun) do { \
|
|
size_t vec_tmp; \
|
|
for (vec_tmp = 0; vec_tmp < (vec).ptr; vec_tmp ++) { \
|
|
(fun)(&(vec).buf[vec_tmp]); \
|
|
} \
|
|
VEC_CLEAR(vec); \
|
|
} while (0)
|
|
|
|
/*
|
|
* Add a value at the end of a vector.
|
|
*/
|
|
#define VEC_ADD(vec, x) do { \
|
|
(vec).buf = vector_expand((vec).buf, sizeof *((vec).buf), \
|
|
&(vec).ptr, &(vec).len, 1); \
|
|
(vec).buf[(vec).ptr ++] = (x); \
|
|
} while (0)
|
|
|
|
/*
|
|
* Add several values at the end of a vector.
|
|
*/
|
|
#define VEC_ADDMANY(vec, xp, num) do { \
|
|
size_t vec_num = (num); \
|
|
(vec).buf = vector_expand((vec).buf, sizeof *((vec).buf), \
|
|
&(vec).ptr, &(vec).len, vec_num); \
|
|
memcpy((vec).buf + (vec).ptr, \
|
|
(xp), vec_num * sizeof *((vec).buf)); \
|
|
(vec).ptr += vec_num; \
|
|
} while (0)
|
|
|
|
/*
|
|
* Access a vector element by index. This is a lvalue, and can be modified.
|
|
*/
|
|
#define VEC_ELT(vec, idx) ((vec).buf[idx])
|
|
|
|
/*
|
|
* Get current vector length.
|
|
*/
|
|
#define VEC_LEN(vec) ((vec).ptr)
|
|
|
|
/*
|
|
* Copy all vector elements into a newly allocated block.
|
|
*/
|
|
#define VEC_TOARRAY(vec) xblobdup((vec).buf, sizeof *((vec).buf) * (vec).ptr)
|
|
|
|
/*
|
|
* Internal function used to handle memory allocations for vectors.
|
|
*/
|
|
void *vector_expand(void *buf,
|
|
size_t esize, size_t *ptr, size_t *len, size_t extra);
|
|
|
|
/*
|
|
* Type for a vector of bytes.
|
|
*/
|
|
typedef VECTOR(unsigned char) bvector;
|
|
|
|
/*
|
|
* Compare two strings for equality; returned value is 1 if the strings
|
|
* are to be considered equal, 0 otherwise. Comparison is case-insensitive
|
|
* (ASCII letters only) and skips some characters (all whitespace, defined
|
|
* as ASCII codes 0 to 32 inclusive, and also '-', '_', '.', '/', '+' and
|
|
* ':').
|
|
*/
|
|
int eqstr(const char *s1, const char *s2);
|
|
|
|
/*
|
|
* Convert a string to a positive integer (size_t). Returned value is
|
|
* (size_t)-1 on error. On error, an explicit error message is printed.
|
|
*/
|
|
size_t parse_size(const char *s);
|
|
|
|
/*
|
|
* Structure for a known protocol version.
|
|
*/
|
|
typedef struct {
|
|
const char *name;
|
|
unsigned version;
|
|
const char *comment;
|
|
} protocol_version;
|
|
|
|
/*
|
|
* Known protocol versions. Last element has a NULL name.
|
|
*/
|
|
extern const protocol_version protocol_versions[];
|
|
|
|
/*
|
|
* Parse a version name. If the name is not recognized, then an error
|
|
* message is printed, and 0 is returned.
|
|
*/
|
|
unsigned parse_version(const char *name, size_t len);
|
|
|
|
/*
|
|
* Type for a known hash function.
|
|
*/
|
|
typedef struct {
|
|
const char *name;
|
|
const br_hash_class *hclass;
|
|
const char *comment;
|
|
} hash_function;
|
|
|
|
/*
|
|
* Known hash functions. Last element has a NULL name.
|
|
*/
|
|
extern const hash_function hash_functions[];
|
|
|
|
/*
|
|
* Parse hash function names. This function expects a comma-separated
|
|
* list of names, and returns a bit mask corresponding to the matched
|
|
* names. If one of the name does not match, or the list is empty, then
|
|
* an error message is printed, and 0 is returned.
|
|
*/
|
|
unsigned parse_hash_functions(const char *arg);
|
|
|
|
/*
|
|
* Get a curve name (by ID). If the curve ID is not known, this returns
|
|
* NULL.
|
|
*/
|
|
const char *get_curve_name(int id);
|
|
|
|
/*
|
|
* Get a curve name (by ID). The name is written in the provided buffer
|
|
* (zero-terminated). If the curve ID is not known, the name is
|
|
* "unknown (***)" where "***" is the decimal value of the identifier.
|
|
* If the name does not fit in the provided buffer, then dst[0] is set
|
|
* to 0 (unless len is 0, in which case nothing is written), and -1 is
|
|
* returned. Otherwise, the name is written in dst[] (with a terminating
|
|
* 0), and this function returns 0.
|
|
*/
|
|
int get_curve_name_ext(int id, char *dst, size_t len);
|
|
|
|
/*
|
|
* Type for a known cipher suite.
|
|
*/
|
|
typedef struct {
|
|
const char *name;
|
|
uint16_t suite;
|
|
unsigned req;
|
|
const char *comment;
|
|
} cipher_suite;
|
|
|
|
/*
|
|
* Known cipher suites. Last element has a NULL name.
|
|
*/
|
|
extern const cipher_suite cipher_suites[];
|
|
|
|
/*
|
|
* Flags for cipher suite requirements.
|
|
*/
|
|
#define REQ_TLS12 0x0001 /* suite needs TLS 1.2 */
|
|
#define REQ_SHA1 0x0002 /* suite needs SHA-1 */
|
|
#define REQ_SHA256 0x0004 /* suite needs SHA-256 */
|
|
#define REQ_SHA384 0x0008 /* suite needs SHA-384 */
|
|
#define REQ_AESCBC 0x0010 /* suite needs AES/CBC encryption */
|
|
#define REQ_AESGCM 0x0020 /* suite needs AES/GCM encryption */
|
|
#define REQ_AESCCM 0x0040 /* suite needs AES/CCM encryption */
|
|
#define REQ_CHAPOL 0x0080 /* suite needs ChaCha20+Poly1305 */
|
|
#define REQ_3DESCBC 0x0100 /* suite needs 3DES/CBC encryption */
|
|
#define REQ_RSAKEYX 0x0200 /* suite uses RSA key exchange */
|
|
#define REQ_ECDHE_RSA 0x0400 /* suite uses ECDHE_RSA key exchange */
|
|
#define REQ_ECDHE_ECDSA 0x0800 /* suite uses ECDHE_ECDSA key exchange */
|
|
#define REQ_ECDH 0x1000 /* suite uses static ECDH key exchange */
|
|
|
|
/*
|
|
* Parse a list of cipher suite names. The names are comma-separated. If
|
|
* one of the name is not recognised, or the list is empty, then an
|
|
* appropriate error message is printed, and NULL is returned.
|
|
* The returned array is allocated with xmalloc() and must be released
|
|
* by the caller. That array is terminated with a dummy entry whose 'name'
|
|
* field is NULL. The number of entries (not counting the dummy entry)
|
|
* is also written into '*num'.
|
|
*/
|
|
cipher_suite *parse_suites(const char *arg, size_t *num);
|
|
|
|
/*
|
|
* Get the name of a cipher suite. Returned value is NULL if the suite is
|
|
* not recognized.
|
|
*/
|
|
const char *get_suite_name(unsigned suite);
|
|
|
|
/*
|
|
* Get the name of a cipher suite. The name is written in the provided
|
|
* buffer; if the suite is not recognised, then the name is
|
|
* "unknown (0x****)" where "****" is the hexadecimal value of the suite.
|
|
* If the name does not fit in the provided buffer, then dst[0] is set
|
|
* to 0 (unless len is 0, in which case nothing is written), and -1 is
|
|
* returned. Otherwise, the name is written in dst[] (with a terminating
|
|
* 0), and this function returns 0.
|
|
*/
|
|
int get_suite_name_ext(unsigned suite, char *dst, size_t len);
|
|
|
|
/*
|
|
* Tell whether a cipher suite uses ECDHE key exchange.
|
|
*/
|
|
int uses_ecdhe(unsigned suite);
|
|
|
|
/*
|
|
* Print out all known names (for protocol versions, cipher suites...).
|
|
*/
|
|
void list_names(void);
|
|
|
|
/*
|
|
* Print out all known elliptic curve names.
|
|
*/
|
|
void list_curves(void);
|
|
|
|
/*
|
|
* Get the symbolic name for an elliptic curve (by ID).
|
|
*/
|
|
const char *ec_curve_name(int curve);
|
|
|
|
/*
|
|
* Get a curve by symbolic name. If the name is not recognized, -1 is
|
|
* returned.
|
|
*/
|
|
int get_curve_by_name(const char *str);
|
|
|
|
/*
|
|
* Get the symbolic name for a hash function name (by ID).
|
|
*/
|
|
const char *hash_function_name(int id);
|
|
|
|
/*
|
|
* Read a file completely. The returned block is allocated with xmalloc()
|
|
* and must be released by the caller.
|
|
* If the file cannot be found or read completely, or is empty, then an
|
|
* appropriate error message is written, and NULL is returned.
|
|
*/
|
|
unsigned char *read_file(const char *fname, size_t *len);
|
|
|
|
/*
|
|
* Write a file completely. This returns 0 on success, -1 on error. On
|
|
* error, an appropriate error message is printed.
|
|
*/
|
|
int write_file(const char *fname, const void *data, size_t len);
|
|
|
|
/*
|
|
* This function returns non-zero if the provided buffer "looks like"
|
|
* a DER-encoded ASN.1 object (criteria: it has the tag for a SEQUENCE
|
|
* with a definite length that matches the total object length).
|
|
*/
|
|
int looks_like_DER(const unsigned char *buf, size_t len);
|
|
|
|
/*
|
|
* Type for a named blob (the 'name' is a normalised PEM header name).
|
|
*/
|
|
typedef struct {
|
|
char *name;
|
|
unsigned char *data;
|
|
size_t data_len;
|
|
} pem_object;
|
|
|
|
/*
|
|
* Release the contents of a named blob (buffer and name).
|
|
*/
|
|
void free_pem_object_contents(pem_object *po);
|
|
|
|
/*
|
|
* Decode a buffer as a PEM file, and return all objects. On error, NULL
|
|
* is returned and an error message is printed. Absence of any object
|
|
* is an error.
|
|
*
|
|
* The returned array is terminated by a dummy object whose 'name' is
|
|
* NULL. The number of objects (not counting the dummy terminator) is
|
|
* written in '*num'.
|
|
*/
|
|
pem_object *decode_pem(const void *src, size_t len, size_t *num);
|
|
|
|
/*
|
|
* Get the certificate(s) from a file. This accepts both a single
|
|
* DER-encoded certificate, and a text file that contains
|
|
* PEM-encoded certificates (and possibly other objects, which are
|
|
* then ignored).
|
|
*
|
|
* On decoding error, or if the file turns out to contain no certificate
|
|
* at all, then an error message is printed and NULL is returned.
|
|
*
|
|
* The returned array, and all referenced buffers, are allocated with
|
|
* xmalloc() and must be released by the caller. The returned array
|
|
* ends with a dummy entry whose 'data' field is NULL.
|
|
* The number of decoded certificates (not counting the dummy entry)
|
|
* is written into '*num'.
|
|
*/
|
|
br_x509_certificate *read_certificates(const char *fname, size_t *num);
|
|
|
|
/*
|
|
* Release certificates. This releases all certificate data arrays,
|
|
* and the whole array as well.
|
|
*/
|
|
void free_certificates(br_x509_certificate *certs, size_t num);
|
|
|
|
/*
|
|
* Interpret a certificate as a trust anchor. The trust anchor is
|
|
* newly allocated with xmalloc() and the caller must release it.
|
|
* On decoding error, an error message is printed, and this function
|
|
* returns NULL.
|
|
*/
|
|
br_x509_trust_anchor *certificate_to_trust_anchor(br_x509_certificate *xc);
|
|
|
|
/*
|
|
* Type for a vector of trust anchors.
|
|
*/
|
|
typedef VECTOR(br_x509_trust_anchor) anchor_list;
|
|
|
|
/*
|
|
* Release contents for a trust anchor (assuming they were dynamically
|
|
* allocated with xmalloc()). The structure itself is NOT released.
|
|
*/
|
|
void free_ta_contents(br_x509_trust_anchor *ta);
|
|
|
|
/*
|
|
* Decode certificates from a file and interpret them as trust anchors.
|
|
* The trust anchors are added to the provided list. The number of found
|
|
* anchors is returned; on error, 0 is returned (finding no anchor at
|
|
* all is considered an error). An appropriate error message is displayed.
|
|
*/
|
|
size_t read_trust_anchors(anchor_list *dst, const char *fname);
|
|
|
|
/*
|
|
* Get the "signer key type" for the certificate (key type of the
|
|
* issuing CA). On error, this prints a message on stderr, and returns 0.
|
|
*/
|
|
int get_cert_signer_algo(br_x509_certificate *xc);
|
|
|
|
/*
|
|
* Special "no anchor" X.509 validator that wraps around another X.509
|
|
* validator and turns "not trusted" error codes into success. This is
|
|
* by definition insecure, but convenient for debug purposes.
|
|
*/
|
|
typedef struct {
|
|
const br_x509_class *vtable;
|
|
const br_x509_class **inner;
|
|
} x509_noanchor_context;
|
|
extern const br_x509_class x509_noanchor_vtable;
|
|
|
|
/*
|
|
* Initialise a "no anchor" X.509 validator.
|
|
*/
|
|
void x509_noanchor_init(x509_noanchor_context *xwc,
|
|
const br_x509_class **inner);
|
|
|
|
/*
|
|
* Aggregate type for a private key.
|
|
*/
|
|
typedef struct {
|
|
int key_type; /* BR_KEYTYPE_RSA or BR_KEYTYPE_EC */
|
|
union {
|
|
br_rsa_private_key rsa;
|
|
br_ec_private_key ec;
|
|
} key;
|
|
} private_key;
|
|
|
|
/*
|
|
* Decode a private key from a file. On error, this prints an error
|
|
* message and returns NULL.
|
|
*/
|
|
private_key *read_private_key(const char *fname);
|
|
|
|
/*
|
|
* Free a private key.
|
|
*/
|
|
void free_private_key(private_key *sk);
|
|
|
|
/*
|
|
* Get the encoded OID for a given hash function (to use with PKCS#1
|
|
* signatures). If the hash function ID is 0 (for MD5+SHA-1), or if
|
|
* the ID is not one of the SHA-* functions (SHA-1, SHA-224, SHA-256,
|
|
* SHA-384, SHA-512), then this function returns NULL.
|
|
*/
|
|
const unsigned char *get_hash_oid(int id);
|
|
|
|
/*
|
|
* Get a hash implementation by ID. This returns NULL if the hash
|
|
* implementation is not available.
|
|
*/
|
|
const br_hash_class *get_hash_impl(int id);
|
|
|
|
/*
|
|
* Find the symbolic name and the description for an error. If 'err' is
|
|
* recognised then the error symbolic name is returned; if 'comment' is
|
|
* not NULL then '*comment' is then set to a descriptive human-readable
|
|
* message. If the error code 'err' is not recognised, then '*comment' is
|
|
* untouched and this function returns NULL.
|
|
*/
|
|
const char *find_error_name(int err, const char **comment);
|
|
|
|
/*
|
|
* Find the symbolic name for an algorithm implementation. Provided
|
|
* pointer should be a pointer to a vtable or to a function, where
|
|
* appropriate. If not recognised, then the string "UNKNOWN" is returned.
|
|
*
|
|
* If 'long_name' is non-zero, then the returned name recalls the
|
|
* algorithm type as well; otherwise, only the core implementation name
|
|
* is returned (e.g. the long name could be 'aes_big_cbcenc' while the
|
|
* short name is 'big').
|
|
*/
|
|
const char *get_algo_name(const void *algo, int long_name);
|
|
|
|
/*
|
|
* Run a SSL engine, with a socket connected to the peer, and using
|
|
* stdin/stdout to exchange application data. The socket must be a
|
|
* non-blocking descriptor.
|
|
*
|
|
* To help with Win32 compatibility, the socket descriptor is provided
|
|
* as an "unsigned long" value.
|
|
*
|
|
* Returned value:
|
|
* 0 SSL connection closed successfully
|
|
* x > 0 SSL error "x"
|
|
* -1 early socket close
|
|
* -2 stdout was closed, or something failed badly
|
|
*/
|
|
int run_ssl_engine(br_ssl_engine_context *eng,
|
|
unsigned long fd, unsigned flags);
|
|
|
|
#define RUN_ENGINE_VERBOSE 0x0001 /* enable verbose messages */
|
|
#define RUN_ENGINE_TRACE 0x0002 /* hex dump of records */
|
|
|
|
/*
|
|
* Do the "client" command. Returned value is 0 on success, -1 on failure.
|
|
* Command-line arguments start _after_ the command name.
|
|
*/
|
|
int do_client(int argc, char *argv[]);
|
|
|
|
/*
|
|
* Do the "server" command. Returned value is 0 on success, -1 on failure.
|
|
* Command-line arguments start _after_ the command name.
|
|
*/
|
|
int do_server(int argc, char *argv[]);
|
|
|
|
/*
|
|
* Do the "verify" command. Returned value is 0 on success, -1 on failure.
|
|
* Command-line arguments start _after_ the command name.
|
|
*/
|
|
int do_verify(int argc, char *argv[]);
|
|
|
|
/*
|
|
* Do the "skey" command. Returned value is 0 on success, -1 on failure.
|
|
* Command-line arguments start _after_ the command name.
|
|
*/
|
|
int do_skey(int argc, char *argv[]);
|
|
|
|
/*
|
|
* Do the "ta" command. Returned value is 0 on success, -1 on failure.
|
|
* Command-line arguments start _after_ the command name.
|
|
*/
|
|
int do_ta(int argc, char *argv[]);
|
|
|
|
/*
|
|
* Do the "chain" command. Returned value is 0 on success, -1 on failure.
|
|
* Command-line arguments start _after_ the command name.
|
|
*/
|
|
int do_chain(int argc, char *argv[]);
|
|
|
|
/*
|
|
* Do the "twrch" command. Returned value is 0 on success, -1 on failure
|
|
* (processing or arguments), or a non-zero exit code. Command-line
|
|
* arguments start _after_ the command name.
|
|
*/
|
|
int do_twrch(int argc, char *argv[]);
|
|
|
|
/*
|
|
* Do the "impl" command. Returned value is 0 on success, -1 on failure.
|
|
* Command-line arguments start _after_ the command name.
|
|
*/
|
|
int do_impl(int argc, char *argv[]);
|
|
|
|
#endif
|