1 /* 2 * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 #include "inner.h" 26 27 /* 28 * Get the appropriate Base64 character for a numeric value in the 29 * 0..63 range. This is constant-time. 30 */ 31 static char 32 b64char(uint32_t x) 33 { 34 /* 35 * Values 0 to 25 map to 0x41..0x5A ('A' to 'Z') 36 * Values 26 to 51 map to 0x61..0x7A ('a' to 'z') 37 * Values 52 to 61 map to 0x30..0x39 ('0' to '9') 38 * Value 62 maps to 0x2B ('+') 39 * Value 63 maps to 0x2F ('/') 40 */ 41 uint32_t a, b, c; 42 43 a = x - 26; 44 b = x - 52; 45 c = x - 62; 46 47 /* 48 * Looking at bits 8..15 of values a, b and c: 49 * 50 * x a b c 51 * --------------------- 52 * 0..25 FF FF FF 53 * 26..51 00 FF FF 54 * 52..61 00 00 FF 55 * 62..63 00 00 00 56 */ 57 return (char)(((x + 0x41) & ((a & b & c) >> 8)) 58 | ((x + (0x61 - 26)) & ((~a & b & c) >> 8)) 59 | ((x - (52 - 0x30)) & ((~a & ~b & c) >> 8)) 60 | ((0x2B + ((x & 1) << 2)) & (~(a | b | c) >> 8))); 61 } 62 63 /* see bearssl_pem.h */ 64 size_t 65 br_pem_encode(void *dest, const void *data, size_t len, 66 const char *banner, unsigned flags) 67 { 68 size_t dlen, banner_len, lines; 69 char *d; 70 unsigned char *buf; 71 size_t u; 72 int off, lim; 73 74 banner_len = strlen(banner); 75 /* FIXME: try to avoid divisions here, as they may pull 76 an extra libc function. */ 77 if ((flags & BR_PEM_LINE64) != 0) { 78 lines = (len + 47) / 48; 79 } else { 80 lines = (len + 56) / 57; 81 } 82 dlen = (banner_len << 1) + 30 + (((len + 2) / 3) << 2) 83 + lines + 2; 84 if ((flags & BR_PEM_CRLF) != 0) { 85 dlen += lines + 2; 86 } 87 88 if (dest == NULL) { 89 return dlen; 90 } 91 92 d = dest; 93 94 /* 95 * We always move the source data to the end of output buffer; 96 * the encoding process never "catches up" except at the very 97 * end. This also handles all conditions of partial or total 98 * overlap. 99 */ 100 buf = (unsigned char *)d + dlen - len; 101 memmove(buf, data, len); 102 103 memcpy(d, "-----BEGIN ", 11); 104 d += 11; 105 memcpy(d, banner, banner_len); 106 d += banner_len; 107 memcpy(d, "-----", 5); 108 d += 5; 109 if ((flags & BR_PEM_CRLF) != 0) { 110 *d ++ = 0x0D; 111 } 112 *d ++ = 0x0A; 113 114 off = 0; 115 lim = (flags & BR_PEM_LINE64) != 0 ? 16 : 19; 116 for (u = 0; (u + 2) < len; u += 3) { 117 uint32_t w; 118 119 w = ((uint32_t)buf[u] << 16) 120 | ((uint32_t)buf[u + 1] << 8) 121 | (uint32_t)buf[u + 2]; 122 *d ++ = b64char(w >> 18); 123 *d ++ = b64char((w >> 12) & 0x3F); 124 *d ++ = b64char((w >> 6) & 0x3F); 125 *d ++ = b64char(w & 0x3F); 126 if (++ off == lim) { 127 off = 0; 128 if ((flags & BR_PEM_CRLF) != 0) { 129 *d ++ = 0x0D; 130 } 131 *d ++ = 0x0A; 132 } 133 } 134 if (u < len) { 135 uint32_t w; 136 137 w = (uint32_t)buf[u] << 16; 138 if (u + 1 < len) { 139 w |= (uint32_t)buf[u + 1] << 8; 140 } 141 *d ++ = b64char(w >> 18); 142 *d ++ = b64char((w >> 12) & 0x3F); 143 if (u + 1 < len) { 144 *d ++ = b64char((w >> 6) & 0x3F); 145 } else { 146 *d ++ = 0x3D; 147 } 148 *d ++ = 0x3D; 149 off ++; 150 } 151 if (off != 0) { 152 if ((flags & BR_PEM_CRLF) != 0) { 153 *d ++ = 0x0D; 154 } 155 *d ++ = 0x0A; 156 } 157 158 memcpy(d, "-----END ", 9); 159 d += 9; 160 memcpy(d, banner, banner_len); 161 d += banner_len; 162 memcpy(d, "-----", 5); 163 d += 5; 164 if ((flags & BR_PEM_CRLF) != 0) { 165 *d ++ = 0x0D; 166 } 167 *d ++ = 0x0A; 168 169 /* Final zero, not counted in returned length. */ 170 *d ++ = 0x00; 171 172 return dlen; 173 } 174