1*cca6fc52SDaniel Fojt /* $OpenBSD: tls_util.c,v 1.14 2019/04/13 18:47:58 tb Exp $ */ 2f5b1c8a1SJohn Marino /* 3f5b1c8a1SJohn Marino * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 472c33676SMaxim Ag * Copyright (c) 2014 Ted Unangst <tedu@openbsd.org> 5f5b1c8a1SJohn Marino * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> 6f5b1c8a1SJohn Marino * 7f5b1c8a1SJohn Marino * Permission to use, copy, modify, and distribute this software for any 8f5b1c8a1SJohn Marino * purpose with or without fee is hereby granted, provided that the above 9f5b1c8a1SJohn Marino * copyright notice and this permission notice appear in all copies. 10f5b1c8a1SJohn Marino * 11f5b1c8a1SJohn Marino * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12f5b1c8a1SJohn Marino * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13f5b1c8a1SJohn Marino * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14f5b1c8a1SJohn Marino * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15f5b1c8a1SJohn Marino * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16f5b1c8a1SJohn Marino * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17f5b1c8a1SJohn Marino * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18f5b1c8a1SJohn Marino */ 19f5b1c8a1SJohn Marino 20f5b1c8a1SJohn Marino #include <sys/stat.h> 21f5b1c8a1SJohn Marino 22f5b1c8a1SJohn Marino #include <stdlib.h> 23f5b1c8a1SJohn Marino #include <unistd.h> 24f5b1c8a1SJohn Marino #include <fcntl.h> 25f5b1c8a1SJohn Marino 26f5b1c8a1SJohn Marino #include "tls.h" 27f5b1c8a1SJohn Marino #include "tls_internal.h" 28f5b1c8a1SJohn Marino 2972c33676SMaxim Ag static void * 3072c33676SMaxim Ag memdup(const void *in, size_t len) 3172c33676SMaxim Ag { 3272c33676SMaxim Ag void *out; 3372c33676SMaxim Ag 3472c33676SMaxim Ag if ((out = malloc(len)) == NULL) 3572c33676SMaxim Ag return NULL; 3672c33676SMaxim Ag memcpy(out, in, len); 3772c33676SMaxim Ag return out; 3872c33676SMaxim Ag } 3972c33676SMaxim Ag 4072c33676SMaxim Ag int 4172c33676SMaxim Ag tls_set_mem(char **dest, size_t *destlen, const void *src, size_t srclen) 4272c33676SMaxim Ag { 4372c33676SMaxim Ag free(*dest); 4472c33676SMaxim Ag *dest = NULL; 4572c33676SMaxim Ag *destlen = 0; 4672c33676SMaxim Ag if (src != NULL) { 4772c33676SMaxim Ag if ((*dest = memdup(src, srclen)) == NULL) 4872c33676SMaxim Ag return -1; 4972c33676SMaxim Ag *destlen = srclen; 5072c33676SMaxim Ag } 5172c33676SMaxim Ag return 0; 5272c33676SMaxim Ag } 5372c33676SMaxim Ag 5472c33676SMaxim Ag int 5572c33676SMaxim Ag tls_set_string(const char **dest, const char *src) 5672c33676SMaxim Ag { 5772c33676SMaxim Ag free((char *)*dest); 5872c33676SMaxim Ag *dest = NULL; 5972c33676SMaxim Ag if (src != NULL) 6072c33676SMaxim Ag if ((*dest = strdup(src)) == NULL) 6172c33676SMaxim Ag return -1; 6272c33676SMaxim Ag return 0; 6372c33676SMaxim Ag } 6472c33676SMaxim Ag 65f5b1c8a1SJohn Marino /* 66f5b1c8a1SJohn Marino * Extract the host and port from a colon separated value. For a literal IPv6 67f5b1c8a1SJohn Marino * address the address must be contained with square braces. If a host and 68f5b1c8a1SJohn Marino * port are successfully extracted, the function will return 0 and the 69f5b1c8a1SJohn Marino * caller is responsible for freeing the host and port. If no port is found 70f5b1c8a1SJohn Marino * then the function will return 1, with both host and port being NULL. 71f5b1c8a1SJohn Marino * On memory allocation failure -1 will be returned. 72f5b1c8a1SJohn Marino */ 73f5b1c8a1SJohn Marino int 74f5b1c8a1SJohn Marino tls_host_port(const char *hostport, char **host, char **port) 75f5b1c8a1SJohn Marino { 76f5b1c8a1SJohn Marino char *h, *p, *s; 77f5b1c8a1SJohn Marino int rv = 1; 78f5b1c8a1SJohn Marino 79f5b1c8a1SJohn Marino *host = NULL; 80f5b1c8a1SJohn Marino *port = NULL; 81f5b1c8a1SJohn Marino 82f5b1c8a1SJohn Marino if ((s = strdup(hostport)) == NULL) 8372c33676SMaxim Ag goto err; 84f5b1c8a1SJohn Marino 85f5b1c8a1SJohn Marino h = p = s; 86f5b1c8a1SJohn Marino 87f5b1c8a1SJohn Marino /* See if this is an IPv6 literal with square braces. */ 88f5b1c8a1SJohn Marino if (p[0] == '[') { 89f5b1c8a1SJohn Marino h++; 90f5b1c8a1SJohn Marino if ((p = strchr(s, ']')) == NULL) 91f5b1c8a1SJohn Marino goto done; 92f5b1c8a1SJohn Marino *p++ = '\0'; 93f5b1c8a1SJohn Marino } 94f5b1c8a1SJohn Marino 95f5b1c8a1SJohn Marino /* Find the port seperator. */ 96f5b1c8a1SJohn Marino if ((p = strchr(p, ':')) == NULL) 97f5b1c8a1SJohn Marino goto done; 98f5b1c8a1SJohn Marino 99f5b1c8a1SJohn Marino /* If there is another separator then we have issues. */ 100f5b1c8a1SJohn Marino if (strchr(p + 1, ':') != NULL) 101f5b1c8a1SJohn Marino goto done; 102f5b1c8a1SJohn Marino 103f5b1c8a1SJohn Marino *p++ = '\0'; 104f5b1c8a1SJohn Marino 105*cca6fc52SDaniel Fojt if (asprintf(host, "%s", h) == -1) { 106*cca6fc52SDaniel Fojt *host = NULL; 10772c33676SMaxim Ag goto err; 108*cca6fc52SDaniel Fojt } 109*cca6fc52SDaniel Fojt if (asprintf(port, "%s", p) == -1) { 110*cca6fc52SDaniel Fojt *port = NULL; 11172c33676SMaxim Ag goto err; 112*cca6fc52SDaniel Fojt } 113f5b1c8a1SJohn Marino 114f5b1c8a1SJohn Marino rv = 0; 115f5b1c8a1SJohn Marino goto done; 116f5b1c8a1SJohn Marino 11772c33676SMaxim Ag err: 118f5b1c8a1SJohn Marino free(*host); 119f5b1c8a1SJohn Marino *host = NULL; 120f5b1c8a1SJohn Marino free(*port); 121f5b1c8a1SJohn Marino *port = NULL; 122f5b1c8a1SJohn Marino rv = -1; 123f5b1c8a1SJohn Marino 124f5b1c8a1SJohn Marino done: 125f5b1c8a1SJohn Marino free(s); 126f5b1c8a1SJohn Marino 127f5b1c8a1SJohn Marino return (rv); 128f5b1c8a1SJohn Marino } 129f5b1c8a1SJohn Marino 13072c33676SMaxim Ag int 131f5b1c8a1SJohn Marino tls_password_cb(char *buf, int size, int rwflag, void *u) 132f5b1c8a1SJohn Marino { 133f5b1c8a1SJohn Marino size_t len; 13472c33676SMaxim Ag 13572c33676SMaxim Ag if (size < 0) 13672c33676SMaxim Ag return (0); 13772c33676SMaxim Ag 138f5b1c8a1SJohn Marino if (u == NULL) { 139f5b1c8a1SJohn Marino memset(buf, 0, size); 140f5b1c8a1SJohn Marino return (0); 141f5b1c8a1SJohn Marino } 14272c33676SMaxim Ag 143f5b1c8a1SJohn Marino if ((len = strlcpy(buf, u, size)) >= (size_t)size) 144f5b1c8a1SJohn Marino return (0); 14572c33676SMaxim Ag 146f5b1c8a1SJohn Marino return (len); 147f5b1c8a1SJohn Marino } 148f5b1c8a1SJohn Marino 149f5b1c8a1SJohn Marino uint8_t * 150f5b1c8a1SJohn Marino tls_load_file(const char *name, size_t *len, char *password) 151f5b1c8a1SJohn Marino { 152f5b1c8a1SJohn Marino FILE *fp; 153f5b1c8a1SJohn Marino EVP_PKEY *key = NULL; 154f5b1c8a1SJohn Marino BIO *bio = NULL; 15572c33676SMaxim Ag char *data; 15672c33676SMaxim Ag uint8_t *buf = NULL; 157f5b1c8a1SJohn Marino struct stat st; 15872c33676SMaxim Ag size_t size = 0; 159f5b1c8a1SJohn Marino int fd = -1; 16072c33676SMaxim Ag ssize_t n; 161f5b1c8a1SJohn Marino 162f5b1c8a1SJohn Marino *len = 0; 163f5b1c8a1SJohn Marino 164f5b1c8a1SJohn Marino if ((fd = open(name, O_RDONLY)) == -1) 165f5b1c8a1SJohn Marino return (NULL); 166f5b1c8a1SJohn Marino 167f5b1c8a1SJohn Marino /* Just load the file into memory without decryption */ 168f5b1c8a1SJohn Marino if (password == NULL) { 169f5b1c8a1SJohn Marino if (fstat(fd, &st) != 0) 17072c33676SMaxim Ag goto err; 17172c33676SMaxim Ag if (st.st_size < 0) 17272c33676SMaxim Ag goto err; 173f5b1c8a1SJohn Marino size = (size_t)st.st_size; 17472c33676SMaxim Ag if ((buf = malloc(size)) == NULL) 17572c33676SMaxim Ag goto err; 17672c33676SMaxim Ag n = read(fd, buf, size); 17772c33676SMaxim Ag if (n < 0 || (size_t)n != size) 17872c33676SMaxim Ag goto err; 179f5b1c8a1SJohn Marino close(fd); 180f5b1c8a1SJohn Marino goto done; 181f5b1c8a1SJohn Marino } 182f5b1c8a1SJohn Marino 183f5b1c8a1SJohn Marino /* Or read the (possibly) encrypted key from file */ 184f5b1c8a1SJohn Marino if ((fp = fdopen(fd, "r")) == NULL) 18572c33676SMaxim Ag goto err; 186f5b1c8a1SJohn Marino fd = -1; 187f5b1c8a1SJohn Marino 188f5b1c8a1SJohn Marino key = PEM_read_PrivateKey(fp, NULL, tls_password_cb, password); 189f5b1c8a1SJohn Marino fclose(fp); 190f5b1c8a1SJohn Marino if (key == NULL) 19172c33676SMaxim Ag goto err; 192f5b1c8a1SJohn Marino 193f5b1c8a1SJohn Marino /* Write unencrypted key to memory buffer */ 194f5b1c8a1SJohn Marino if ((bio = BIO_new(BIO_s_mem())) == NULL) 19572c33676SMaxim Ag goto err; 196f5b1c8a1SJohn Marino if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL)) 19772c33676SMaxim Ag goto err; 198f5b1c8a1SJohn Marino if ((size = BIO_get_mem_data(bio, &data)) <= 0) 19972c33676SMaxim Ag goto err; 20072c33676SMaxim Ag if ((buf = malloc(size)) == NULL) 20172c33676SMaxim Ag goto err; 202f5b1c8a1SJohn Marino memcpy(buf, data, size); 203f5b1c8a1SJohn Marino 204f5b1c8a1SJohn Marino BIO_free_all(bio); 205f5b1c8a1SJohn Marino EVP_PKEY_free(key); 206f5b1c8a1SJohn Marino 207f5b1c8a1SJohn Marino done: 208f5b1c8a1SJohn Marino *len = size; 209f5b1c8a1SJohn Marino return (buf); 210f5b1c8a1SJohn Marino 21172c33676SMaxim Ag err: 212f5b1c8a1SJohn Marino if (fd != -1) 213f5b1c8a1SJohn Marino close(fd); 21472c33676SMaxim Ag freezero(buf, size); 215f5b1c8a1SJohn Marino BIO_free_all(bio); 216f5b1c8a1SJohn Marino EVP_PKEY_free(key); 217f5b1c8a1SJohn Marino 218f5b1c8a1SJohn Marino return (NULL); 219f5b1c8a1SJohn Marino } 22072c33676SMaxim Ag 22172c33676SMaxim Ag void 22272c33676SMaxim Ag tls_unload_file(uint8_t *buf, size_t len) 22372c33676SMaxim Ag { 22472c33676SMaxim Ag freezero(buf, len); 22572c33676SMaxim Ag } 226