From 58daab21cd043e1dc37024a7f99b396788372918 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 9 Mar 2024 14:19:48 +0100 Subject: Merging upstream version 1.44.3. Signed-off-by: Daniel Baumann --- web/server/h2o/libh2o/deps/picotls/lib/pembase64.c | 373 +++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 web/server/h2o/libh2o/deps/picotls/lib/pembase64.c (limited to 'web/server/h2o/libh2o/deps/picotls/lib/pembase64.c') diff --git a/web/server/h2o/libh2o/deps/picotls/lib/pembase64.c b/web/server/h2o/libh2o/deps/picotls/lib/pembase64.c new file mode 100644 index 000000000..de44c5386 --- /dev/null +++ b/web/server/h2o/libh2o/deps/picotls/lib/pembase64.c @@ -0,0 +1,373 @@ +/* +* Copyright (c) 2016 Christian Huitema +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/* + * Manage Base64 encoding. + */ +#ifdef _WINDOWS +#include "wincompat.h" +#else +#include +#endif +#include +#include +#include +#include +#include "picotls.h" +#include "picotls/pembase64.h" + +static char ptls_base64_alphabet[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + +static char ptls_base64_values[] = { + /* 0x00 to 0x0F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + /* 0x10 to 0x1F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + /* 0x20 to 0x2F. '+' at 2B, '/' at 2F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + /* 0x30 to 0x3F -- digits 0 to 9 at 0x30 to 0x39*/ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + /* 0x40 to 0x4F -- chars 'A' to 'O' at 0x41 to 0x4F */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + /* 0x50 to 0x5F -- chars 'P' to 'Z' at 0x50 to 0x5A */ + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + /* 0x60 to 0x6F -- chars 'a' to 'o' at 0x61 to 0x6F */ + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + /* 0x70 to 0x7F -- chars 'p' to 'z' at 0x70 to 0x7A */ + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1}; + +static void ptls_base64_cell(const uint8_t *data, char *text) +{ + int n[4]; + + n[0] = data[0] >> 2; + n[1] = ((data[0] & 3) << 4) | (data[1] >> 4); + n[2] = ((data[1] & 15) << 2) | (data[2] >> 6); + n[3] = data[2] & 63; + + for (int i = 0; i < 4; i++) { + text[i] = ptls_base64_alphabet[n[i]]; + } +} + +size_t ptls_base64_howlong(size_t data_length) +{ + return (((data_length + 2) / 3) * 4); +} + +int ptls_base64_encode(const uint8_t *data, size_t data_len, char *ptls_base64_text) +{ + int l = 0; + int lt = 0; + + while ((data_len - l) >= 3) { + ptls_base64_cell(data + l, ptls_base64_text + lt); + l += 3; + lt += 4; + } + + switch (data_len - l) { + case 0: + break; + case 1: + ptls_base64_text[lt++] = ptls_base64_alphabet[data[l] >> 2]; + ptls_base64_text[lt++] = ptls_base64_alphabet[(data[l] & 3) << 4]; + ptls_base64_text[lt++] = '='; + ptls_base64_text[lt++] = '='; + break; + case 2: + ptls_base64_text[lt++] = ptls_base64_alphabet[data[l] >> 2]; + ptls_base64_text[lt++] = ptls_base64_alphabet[((data[l] & 3) << 4) | (data[l + 1] >> 4)]; + ptls_base64_text[lt++] = ptls_base64_alphabet[((data[l + 1] & 15) << 2)]; + ptls_base64_text[lt++] = '='; + break; + default: + break; + } + ptls_base64_text[lt++] = 0; + + return lt; +} + +/* + * Take into input a line of text, so as to work by increments. + * The intermediate text of the decoding is kept in a state variable. + * The decoded data is accumulated in a PTLS buffer. + * The parsing is consistent with the lax definition in RFC 7468 + */ + +void ptls_base64_decode_init(ptls_base64_decode_state_t *state) +{ + state->nbc = 0; + state->nbo = 3; + state->v = 0; + state->status = PTLS_BASE64_DECODE_IN_PROGRESS; +} + +int ptls_base64_decode(const char *text, ptls_base64_decode_state_t *state, ptls_buffer_t *buf) +{ + int ret = 0; + uint8_t decoded[3]; + size_t text_index = 0; + int c; + char vc; + + /* skip initial blanks */ + while (text[text_index] != 0) { + c = text[text_index]; + + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') { + text_index++; + } else { + break; + } + } + + while (text[text_index] != 0 && ret == 0 && state->status == PTLS_BASE64_DECODE_IN_PROGRESS) { + c = text[text_index++]; + + vc = 0 < c && c < 0x7f ? ptls_base64_values[c] : -1; + if (vc == -1) { + if (state->nbc == 2 && c == '=' && text[text_index] == '=') { + state->nbc = 4; + text_index++; + state->nbo = 1; + state->v <<= 12; + } else if (state->nbc == 3 && c == '=') { + state->nbc = 4; + state->nbo = 2; + state->v <<= 6; + } else { + /* Skip final blanks */ + text_index--; + while (text[text_index] != 0) { + c = text[text_index++]; + + if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0x0B || c == 0x0C) { + continue; + } + } + + /* Should now be at end of buffer */ + if (text[text_index] == 0) { + break; + } else { + /* Not at end of buffer, signal a decoding error */ + state->nbo = 0; + state->status = PTLS_BASE64_DECODE_FAILED; + ret = PTLS_ERROR_INCORRECT_BASE64; + } + } + } else { + state->nbc++; + state->v <<= 6; + state->v |= vc; + } + + if (ret == 0 && state->nbc == 4) { + /* Convert to up to 3 octets */ + for (int j = 0; j < state->nbo; j++) { + decoded[j] = (uint8_t)(state->v >> (8 * (2 - j))); + } + + ret = ptls_buffer__do_pushv(buf, decoded, state->nbo); + + if (ret == 0) { + /* test for fin or continuation */ + if (state->nbo < 3) { + /* Check that there are only trainling blanks on this line */ + while (text[text_index] != 0) { + c = text[text_index++]; + + if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0x0B || c == 0x0C) { + continue; + } + } + if (text[text_index] == 0) { + state->status = PTLS_BASE64_DECODE_DONE; + } else { + state->status = PTLS_BASE64_DECODE_FAILED; + ret = PTLS_ERROR_INCORRECT_BASE64; + } + break; + } else { + state->v = 0; + state->nbo = 3; + state->nbc = 0; + } + } + } + } + return ret; +} + +/* + * Reading a PEM file, to get an object: + * + * - Find first object, get the object name. + * - If object label is what the application expects, parse, else skip to end. + * + * The following labels are defined in RFC 7468: + * + * Sec. Label ASN.1 Type Reference Module + * ----+----------------------+-----------------------+---------+---------- + * 5 CERTIFICATE Certificate [RFC5280] id-pkix1-e + * 6 X509 CRL CertificateList [RFC5280] id-pkix1-e + * 7 CERTIFICATE REQUEST CertificationRequest [RFC2986] id-pkcs10 + * 8 PKCS7 ContentInfo [RFC2315] id-pkcs7* + * 9 CMS ContentInfo [RFC5652] id-cms2004 + * 10 PRIVATE KEY PrivateKeyInfo ::= [RFC5208] id-pkcs8 + * OneAsymmetricKey [RFC5958] id-aKPV1 + * 11 ENCRYPTED PRIVATE KEY EncryptedPrivateKeyInfo [RFC5958] id-aKPV1 + * 12 ATTRIBUTE CERTIFICATE AttributeCertificate [RFC5755] id-acv2 + * 13 PUBLIC KEY SubjectPublicKeyInfo [RFC5280] id-pkix1-e + */ + +static int ptls_compare_separator_line(const char *line, const char *begin_or_end, const char *label) +{ + int ret = strncmp(line, "-----", 5); + size_t text_index = 5; + + if (ret == 0) { + size_t begin_or_end_length = strlen(begin_or_end); + ret = strncmp(line + text_index, begin_or_end, begin_or_end_length); + text_index += begin_or_end_length; + } + + if (ret == 0) { + ret = line[text_index] - ' '; + text_index++; + } + + if (ret == 0) { + size_t label_length = strlen(label); + ret = strncmp(line + text_index, label, label_length); + text_index += label_length; + } + + if (ret == 0) { + ret = strncmp(line + text_index, "-----", 5); + } + + return ret; +} + +static int ptls_get_pem_object(FILE *F, const char *label, ptls_buffer_t *buf) +{ + int ret = PTLS_ERROR_PEM_LABEL_NOT_FOUND; + char line[256]; + ptls_base64_decode_state_t state; + + /* Get the label on a line by itself */ + while (fgets(line, 256, F)) { + if (ptls_compare_separator_line(line, "BEGIN", label) == 0) { + ret = 0; + ptls_base64_decode_init(&state); + break; + } + } + /* Get the data in the buffer */ + while (ret == 0 && fgets(line, 256, F)) { + if (ptls_compare_separator_line(line, "END", label) == 0) { + if (state.status == PTLS_BASE64_DECODE_DONE || (state.status == PTLS_BASE64_DECODE_IN_PROGRESS && state.nbc == 0)) { + ret = 0; + } else { + ret = PTLS_ERROR_INCORRECT_BASE64; + } + break; + } else { + ret = ptls_base64_decode(line, &state, buf); + } + } + + return ret; +} + +int ptls_load_pem_objects(char const *pem_fname, const char *label, ptls_iovec_t *list, size_t list_max, size_t *nb_objects) +{ + FILE *F; + int ret = 0; + size_t count = 0; +#ifdef _WINDOWS + errno_t err = fopen_s(&F, pem_fname, "r"); + if (err != 0) { + ret = -1; + } +#else + F = fopen(pem_fname, "r"); + if (F == NULL) { + ret = -1; + } +#endif + + *nb_objects = 0; + + if (ret == 0) { + while (count < list_max) { + ptls_buffer_t buf; + + ptls_buffer_init(&buf, "", 0); + + ret = ptls_get_pem_object(F, label, &buf); + + if (ret == 0) { + if (buf.off > 0 && buf.is_allocated) { + list[count].base = buf.base; + list[count].len = buf.off; + count++; + } else { + ptls_buffer_dispose(&buf); + } + } else { + ptls_buffer_dispose(&buf); + break; + } + } + } + + if (ret == PTLS_ERROR_PEM_LABEL_NOT_FOUND && count > 0) { + ret = 0; + } + + *nb_objects = count; + + if (F != NULL) { + fclose(F); + } + + return ret; +} + +#define PTLS_MAX_CERTS_IN_CONTEXT 16 + +int ptls_load_certificates(ptls_context_t *ctx, char *cert_pem_file) +{ + int ret = 0; + + ctx->certificates.list = (ptls_iovec_t *)malloc(PTLS_MAX_CERTS_IN_CONTEXT * sizeof(ptls_iovec_t)); + + if (ctx->certificates.list == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + } else { + ret = ptls_load_pem_objects(cert_pem_file, "CERTIFICATE", ctx->certificates.list, PTLS_MAX_CERTS_IN_CONTEXT, + &ctx->certificates.count); + } + + return ret; +} -- cgit v1.2.3