/* * Copyright (c) 2016 Thomas Pornin * * 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 #include #include #include #elif !defined(STAND_H) #include #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