/* * 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. */ #include "brssl.h" #include "bearssl.h" /* see brssl.h */ const protocol_version protocol_versions[] = { { "tls10", BR_TLS10, "TLS 1.0" }, { "tls11", BR_TLS11, "TLS 1.1" }, { "tls12", BR_TLS12, "TLS 1.2" }, { NULL, 0, NULL } }; /* see brssl.h */ const hash_function hash_functions[] = { { "md5", &br_md5_vtable, "MD5" }, { "sha1", &br_sha1_vtable, "SHA-1" }, { "sha224", &br_sha224_vtable, "SHA-224" }, { "sha256", &br_sha256_vtable, "SHA-256" }, { "sha384", &br_sha384_vtable, "SHA-384" }, { "sha512", &br_sha512_vtable, "SHA-512" }, { NULL, 0, NULL } }; /* see brssl.h */ const cipher_suite cipher_suites[] = { { "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, REQ_ECDHE_ECDSA | REQ_AESGCM | REQ_SHA256 | REQ_TLS12, "ECDHE with ECDSA, AES-128/GCM encryption (TLS 1.2+)" }, { "ECDHE_RSA_WITH_AES_128_GCM_SHA256", BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, REQ_ECDHE_RSA | REQ_AESGCM | REQ_SHA256 | REQ_TLS12, "ECDHE with RSA, AES-128/GCM encryption (TLS 1.2+)" }, { "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, REQ_ECDHE_ECDSA | REQ_AESGCM | REQ_SHA384 | REQ_TLS12, "ECDHE with ECDSA, AES-256/GCM encryption (TLS 1.2+)" }, { "ECDHE_RSA_WITH_AES_256_GCM_SHA384", BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, REQ_ECDHE_RSA | REQ_AESGCM | REQ_SHA384 | REQ_TLS12, "ECDHE with RSA, AES-256/GCM encryption (TLS 1.2+)" }, { "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA256 | REQ_TLS12, "ECDHE with ECDSA, AES-128/CBC + SHA-256 (TLS 1.2+)" }, { "ECDHE_RSA_WITH_AES_128_CBC_SHA256", BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA256 | REQ_TLS12, "ECDHE with RSA, AES-128/CBC + SHA-256 (TLS 1.2+)" }, { "ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA384 | REQ_TLS12, "ECDHE with ECDSA, AES-256/CBC + SHA-384 (TLS 1.2+)" }, { "ECDHE_RSA_WITH_AES_256_CBC_SHA384", BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA384 | REQ_TLS12, "ECDHE with RSA, AES-256/CBC + SHA-384 (TLS 1.2+)" }, { "ECDHE_ECDSA_WITH_AES_128_CBC_SHA", BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA1, "ECDHE with ECDSA, AES-128/CBC + SHA-1" }, { "ECDHE_RSA_WITH_AES_128_CBC_SHA", BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA1, "ECDHE with RSA, AES-128/CBC + SHA-1" }, { "ECDHE_ECDSA_WITH_AES_256_CBC_SHA", BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA1, "ECDHE with ECDSA, AES-256/CBC + SHA-1" }, { "ECDHE_RSA_WITH_AES_256_CBC_SHA", BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA1, "ECDHE with RSA, AES-256/CBC + SHA-1" }, { "ECDH_ECDSA_WITH_AES_128_GCM_SHA256", BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, REQ_ECDH | REQ_AESGCM | REQ_SHA256 | REQ_TLS12, "ECDH key exchange (EC cert), AES-128/GCM (TLS 1.2+)" }, { "ECDH_RSA_WITH_AES_128_GCM_SHA256", BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, REQ_ECDH | REQ_AESGCM | REQ_SHA256 | REQ_TLS12, "ECDH key exchange (RSA cert), AES-128/GCM (TLS 1.2+)" }, { "ECDH_ECDSA_WITH_AES_256_GCM_SHA384", BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, REQ_ECDH | REQ_AESGCM | REQ_SHA384 | REQ_TLS12, "ECDH key exchange (EC cert), AES-256/GCM (TLS 1.2+)" }, { "ECDH_RSA_WITH_AES_256_GCM_SHA384", BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, REQ_ECDH | REQ_AESGCM | REQ_SHA384 | REQ_TLS12, "ECDH key exchange (RSA cert), AES-256/GCM (TLS 1.2+)" }, { "ECDH_ECDSA_WITH_AES_128_CBC_SHA256", BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, REQ_ECDH | REQ_AESCBC | REQ_SHA256 | REQ_TLS12, "ECDH key exchange (EC cert), AES-128/CBC + HMAC/SHA-256 (TLS 1.2+)" }, { "ECDH_RSA_WITH_AES_128_CBC_SHA256", BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, REQ_ECDH | REQ_AESCBC | REQ_SHA256 | REQ_TLS12, "ECDH key exchange (RSA cert), AES-128/CBC + HMAC/SHA-256 (TLS 1.2+)" }, { "ECDH_ECDSA_WITH_AES_256_CBC_SHA384", BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, REQ_ECDH | REQ_AESCBC | REQ_SHA384 | REQ_TLS12, "ECDH key exchange (EC cert), AES-256/CBC + HMAC/SHA-384 (TLS 1.2+)" }, { "ECDH_RSA_WITH_AES_256_CBC_SHA384", BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, REQ_ECDH | REQ_AESCBC | REQ_SHA384 | REQ_TLS12, "ECDH key exchange (RSA cert), AES-256/CBC + HMAC/SHA-384 (TLS 1.2+)" }, { "ECDH_ECDSA_WITH_AES_128_CBC_SHA", BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, REQ_ECDH | REQ_AESCBC | REQ_SHA1, "ECDH key exchange (EC cert), AES-128/CBC + HMAC/SHA-1" }, { "ECDH_RSA_WITH_AES_128_CBC_SHA", BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, REQ_ECDH | REQ_AESCBC | REQ_SHA1, "ECDH key exchange (RSA cert), AES-128/CBC + HMAC/SHA-1" }, { "ECDH_ECDSA_WITH_AES_256_CBC_SHA", BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, REQ_ECDH | REQ_AESCBC | REQ_SHA1, "ECDH key exchange (EC cert), AES-256/CBC + HMAC/SHA-1" }, { "ECDH_RSA_WITH_AES_256_CBC_SHA", BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, REQ_ECDH | REQ_AESCBC | REQ_SHA1, "ECDH key exchange (RSA cert), AES-256/CBC + HMAC/SHA-1" }, { "RSA_WITH_AES_128_GCM_SHA256", BR_TLS_RSA_WITH_AES_128_GCM_SHA256, REQ_RSAKEYX | REQ_AESGCM | REQ_SHA256 | REQ_TLS12, "RSA key exchange, AES-128/GCM encryption (TLS 1.2+)" }, { "RSA_WITH_AES_256_GCM_SHA384", BR_TLS_RSA_WITH_AES_256_GCM_SHA384, REQ_RSAKEYX | REQ_AESGCM | REQ_SHA384 | REQ_TLS12, "RSA key exchange, AES-256/GCM encryption (TLS 1.2+)" }, { "RSA_WITH_AES_128_CBC_SHA256", BR_TLS_RSA_WITH_AES_128_CBC_SHA256, REQ_RSAKEYX | REQ_AESCBC | REQ_SHA256 | REQ_TLS12, "RSA key exchange, AES-128/CBC + HMAC/SHA-256 (TLS 1.2+)" }, { "RSA_WITH_AES_256_CBC_SHA256", BR_TLS_RSA_WITH_AES_256_CBC_SHA256, REQ_RSAKEYX | REQ_AESCBC | REQ_SHA256 | REQ_TLS12, "RSA key exchange, AES-256/CBC + HMAC/SHA-256 (TLS 1.2+)" }, { "RSA_WITH_AES_128_CBC_SHA", BR_TLS_RSA_WITH_AES_128_CBC_SHA, REQ_RSAKEYX | REQ_AESCBC | REQ_SHA1, "RSA key exchange, AES-128/CBC + HMAC/SHA-1" }, { "RSA_WITH_AES_256_CBC_SHA", BR_TLS_RSA_WITH_AES_256_CBC_SHA, REQ_RSAKEYX | REQ_AESCBC | REQ_SHA1, "RSA key exchange, AES-256/CBC + HMAC/SHA-1" }, { "ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, REQ_ECDHE_ECDSA | REQ_3DESCBC | REQ_SHA1, "ECDHE with ECDSA, 3DES/CBC + SHA-1" }, { "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, REQ_ECDHE_RSA | REQ_3DESCBC | REQ_SHA1, "ECDHE with RSA, 3DES/CBC + SHA-1" }, { "ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, REQ_ECDH | REQ_3DESCBC | REQ_SHA1, "ECDH key exchange (EC cert), 3DES/CBC + HMAC/SHA-1" }, { "ECDH_RSA_WITH_3DES_EDE_CBC_SHA", BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, REQ_ECDH | REQ_3DESCBC | REQ_SHA1, "ECDH key exchange (RSA cert), 3DES/CBC + HMAC/SHA-1" }, { "RSA_WITH_3DES_EDE_CBC_SHA", BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA, REQ_RSAKEYX | REQ_3DESCBC | REQ_SHA1, "RSA key exchange, 3DES/CBC + HMAC/SHA-1" }, { NULL, 0, 0, NULL } }; /* see brssl.h */ const char * get_suite_name(unsigned suite) { size_t u; for (u = 0; cipher_suites[u].name; u ++) { if (cipher_suites[u].suite == suite) { return cipher_suites[u].name; } } return NULL; } /* see brssl.h */ int get_suite_name_ext(unsigned suite, char *dst, size_t len) { const char *name; char tmp[30]; size_t n; name = get_suite_name(suite); if (name == NULL) { sprintf(tmp, "unknown (0x%04X)", suite); name = tmp; } n = 1 + strlen(name); if (n > len) { if (len > 0) { dst[0] = 0; } return -1; } memcpy(dst, name, n); return 0; } /* see brssl.h */ void list_names(void) { size_t u; printf("Protocol versions:\n"); for (u = 0; protocol_versions[u].name; u ++) { printf(" %-8s %s\n", protocol_versions[u].name, protocol_versions[u].comment); } printf("Hash functions:\n"); for (u = 0; hash_functions[u].name; u ++) { printf(" %-8s %s\n", hash_functions[u].name, hash_functions[u].comment); } printf("Cipher suites:\n"); for (u = 0; cipher_suites[u].name; u ++) { printf(" %s\n %s\n", cipher_suites[u].name, cipher_suites[u].comment); } } static int is_ign(int c) { if (c == 0) { return 0; } if (c <= 32 || c == '-' || c == '_' || c == '.' || c == '/' || c == '+' || c == ':') { return 1; } return 0; } /* * Get next non-ignored character, normalised: * ASCII letters are converted to lowercase * control characters, space, '-', '_', '.', '/', '+' and ':' are ignored * A terminating zero is returned as 0. */ static int next_char(const char **ps, const char *limit) { for (;;) { int c; if (*ps == limit) { return 0; } c = *(*ps) ++; if (c == 0) { return 0; } if (c >= 'A' && c <= 'Z') { c += 'a' - 'A'; } if (!is_ign(c)) { return c; } } } /* * Partial string equality comparison, with normalisation. */ static int eqstr_chunk(const char *s1, size_t s1_len, const char *s2, size_t s2_len) { const char *lim1, *lim2; lim1 = s1 + s1_len; lim2 = s2 + s2_len; for (;;) { int c1, c2; c1 = next_char(&s1, lim1); c2 = next_char(&s2, lim2); if (c1 != c2) { return 0; } if (c1 == 0) { return 1; } } return 1; } /* see brssl.h */ int eqstr(const char *s1, const char *s2) { return eqstr_chunk(s1, strlen(s1), s2, strlen(s2)); } /* * Comma-separated list enumeration. This returns a pointer to the first * word in the string, skipping leading ignored characters. '*len' is * set to the word length (not counting trailing ignored characters). * '*str' is updated to point to immediately after the next comma, or to * the terminating zero, whichever comes first. * * Empty words are skipped. If there is no next non-empty word, then this * function returns NULL and sets *len to 0. */ static const char * next_word(const char **str, size_t *len) { int c; const char *begin; size_t u; /* * Find next non-ignored character which is not a comma. */ for (;;) { c = **str; if (c == 0) { *len = 0; return NULL; } if (!is_ign(c) && c != ',') { break; } (*str) ++; } /* * Find next comma or terminator. */ begin = *str; for (;;) { c = *(*str); if (c == 0 || c == ',') { break; } (*str) ++; } /* * Remove trailing ignored characters. */ u = (size_t)(*str - begin); while (u > 0 && is_ign(begin[u - 1])) { u --; } if (c == ',') { (*str) ++; } *len = u; return begin; } /* see brssl.h */ unsigned parse_version(const char *name, size_t len) { size_t u; for (u = 0;; u ++) { const char *ref; ref = protocol_versions[u].name; if (ref == NULL) { fprintf(stderr, "ERROR: unrecognised protocol" " version name: '%s'\n", name); return 0; } if (eqstr_chunk(ref, strlen(ref), name, len)) { return protocol_versions[u].version; } } } /* see brssl.h */ unsigned parse_hash_functions(const char *arg) { unsigned r; r = 0; for (;;) { const char *name; size_t len; size_t u; name = next_word(&arg, &len); if (name == NULL) { break; } for (u = 0;; u ++) { const char *ref; ref = hash_functions[u].name; if (ref == 0) { fprintf(stderr, "ERROR: unrecognised" " hash function name: '"); fwrite(name, 1, len, stderr); fprintf(stderr, "'\n"); return 0; } if (eqstr_chunk(ref, strlen(ref), name, len)) { int id; id = (hash_functions[u].hclass->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK; r |= (unsigned)1 << id; break; } } } if (r == 0) { fprintf(stderr, "ERROR: no hash function name provided\n"); } return r; } /* see brssl.h */ cipher_suite * parse_suites(const char *arg, size_t *num) { VECTOR(cipher_suite) suites = VEC_INIT; cipher_suite *r; for (;;) { const char *name; size_t u, len; name = next_word(&arg, &len); if (name == NULL) { break; } for (u = 0;; u ++) { const char *ref; ref = cipher_suites[u].name; if (ref == NULL) { fprintf(stderr, "ERROR: unrecognised" " cipher suite '"); fwrite(name, 1, len, stderr); fprintf(stderr, "'\n"); return 0; } if (eqstr_chunk(ref, strlen(ref), name, len)) { VEC_ADD(suites, cipher_suites[u]); break; } } } if (VEC_LEN(suites) == 0) { fprintf(stderr, "ERROR: no cipher suite provided\n"); } r = VEC_TOARRAY(suites); *num = VEC_LEN(suites); VEC_CLEAR(suites); return r; } /* see brssl.h */ const char * ec_curve_name(int curve) { switch (curve) { case BR_EC_sect163k1: return "sect163k1"; case BR_EC_sect163r1: return "sect163r1"; case BR_EC_sect163r2: return "sect163r2"; case BR_EC_sect193r1: return "sect193r1"; case BR_EC_sect193r2: return "sect193r2"; case BR_EC_sect233k1: return "sect233k1"; case BR_EC_sect233r1: return "sect233r1"; case BR_EC_sect239k1: return "sect239k1"; case BR_EC_sect283k1: return "sect283k1"; case BR_EC_sect283r1: return "sect283r1"; case BR_EC_sect409k1: return "sect409k1"; case BR_EC_sect409r1: return "sect409r1"; case BR_EC_sect571k1: return "sect571k1"; case BR_EC_sect571r1: return "sect571r1"; case BR_EC_secp160k1: return "secp160k1"; case BR_EC_secp160r1: return "secp160r1"; case BR_EC_secp160r2: return "secp160r2"; case BR_EC_secp192k1: return "secp192k1"; case BR_EC_secp192r1: return "secp192r1"; case BR_EC_secp224k1: return "secp224k1"; case BR_EC_secp224r1: return "secp224r1"; case BR_EC_secp256k1: return "secp256k1"; case BR_EC_secp256r1: return "secp256r1"; case BR_EC_secp384r1: return "secp384r1"; case BR_EC_secp521r1: return "secp521r1"; case BR_EC_brainpoolP256r1: return "brainpoolP256r1"; case BR_EC_brainpoolP384r1: return "brainpoolP384r1"; case BR_EC_brainpoolP512r1: return "brainpoolP512r1"; default: return "unknown"; } }