2 pem.c -- PEM encoding and decoding
3 Copyright (C) 2007-2022 Guus Sliepen <guus@tinc-vpn.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "../system.h"
25 // Base64 decoding table
27 static const uint8_t b64dec[128] = {
28 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
29 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
30 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
31 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
32 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
33 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
34 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
35 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
36 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
37 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
38 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
39 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
40 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
41 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
42 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
43 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
44 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
45 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
46 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
47 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
48 0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
52 static const char b64enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
53 "abcdefghijklmnopqrstuvwxyz"
56 // Heavily based on code by Jouni Malinen <j@w1.fi>
57 // https://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c
58 static size_t b64encode(char *dst, const void *src, const size_t length) {
59 const uint8_t *end = (const uint8_t *)src + length;
60 const uint8_t *in = src;
63 while(end - in >= 3) {
64 *pos++ = b64enc[in[0] >> 2];
65 *pos++ = b64enc[((in[0] & 0x03) << 4) | (in[1] >> 4)];
66 *pos++ = b64enc[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
67 *pos++ = b64enc[in[2] & 0x3f];
72 *pos++ = b64enc[in[0] >> 2];
75 *pos++ = b64enc[(in[0] & 0x03) << 4];
78 *pos++ = b64enc[((in[0] & 0x03) << 4) | (in[1] >> 4)];
79 *pos++ = b64enc[(in[1] & 0x0f) << 2];
91 bool pem_encode(FILE *fp, const char *header, uint8_t *buf, size_t size) {
92 if(fprintf(fp, "-----BEGIN %s-----\n", header) <= 0) {
96 char b64[B64_SIZE(size)];
97 const size_t b64len = b64encode(b64, buf, size);
99 for(char *p = b64; p < b64 + b64len; p += 64) {
100 if(fprintf(fp, "%.64s\n", p) <= 0) {
105 return fprintf(fp, "-----END %s-----\n", header) > 0;
108 bool pem_decode(FILE *fp, const char *header, uint8_t *buf, size_t size, size_t *outsize) {
116 if(!fgets(line, sizeof(line), fp)) {
120 if(!decode && !strncmp(line, "-----BEGIN ", 11)) {
121 if(!strncmp(line + 11, header, strlen(header))) {
128 if(decode && !strncmp(line, "-----END", 8)) {
136 for(i = 0; line[i] >= ' '; i++) {
137 if((signed char)line[i] < 0 || b64dec[(int)line[i]] == 0xff) {
141 word |= b64dec[(int)line[i]] << shift;
150 buf[j++] = word >> 8;
151 word = (uint16_t)(word << 8);