├── .clang-format ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── neverbleed.c ├── neverbleed.h └── test.c /.clang-format: -------------------------------------------------------------------------------- 1 | # requires clang-format >= 3.6 2 | BasedOnStyle: "LLVM" 3 | IndentWidth: 4 4 | ColumnLimit: 132 5 | BreakBeforeBraces: Linux 6 | AllowShortFunctionsOnASingleLine: None 7 | SortIncludes: false 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Kazuho Oku, DeNA Co., Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC?= cc 2 | CFLAGS+= -Wall -fsanitize=address -fstack-protector -g 3 | LIBS+= -lpthread -lssl -lcrypto 4 | TARGET= test-neverbleed 5 | OBJS= test.o neverbleed.o 6 | 7 | all: $(TARGET) 8 | 9 | .c.o: 10 | $(CC) $(CFLAGS) -c $< 11 | 12 | $(TARGET): $(OBJS) 13 | $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(LDFLAGS) 14 | 15 | clean: 16 | rm -fr $(OBJS) $(TARGET) 17 | 18 | .PHONY: clean 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Neverbleed 2 | =============== 3 | 4 | Neverbleed is an [OpenSSL engine](https://www.openssl.org/docs/man1.0.2/crypto/engine.html) that runs RSA private key operations in an isolated process, thereby minimizing the risk of private key leak in case of vulnerability such as [Heartbleed](http://heartbleed.com/). 5 | 6 | The engine is known to work together with existing versions of OpenSSL or LibreSSL, with minimal changes to the server source code. 7 | 8 | FAQ 9 | --- 10 | 11 | ### Q. How much is the overhead? 12 | 13 | Virtually none. 14 | 15 | Generally speaking, private key operations are much more heavier than the overhead of inter-process communication. 16 | On my Linux VM running on Core i7 @ 2.4GHz (MacBook Pro 15" Late 2013), OpenSSL 1.0.2 without privilege separation processes 319.56 full TLS handshakes per second, whereas OpenSSL with privilege separation processes 316.72 handshakes per second (note: RSA key length: 2,048 bits, selected cipher-suite: ECDHE-RSA-AES128-GCM-SHA256). 17 | 18 | ### Q. Why does the library only protect the private keys? 19 | 20 | Because private keys are the only _long-term_ secret being used for encrypting and/or digitally-signing the communication. 21 | 22 | Depending on how OpenSSL is used, it might be beneficial to separate symmetric cipher operations or TLS operations as a whole. 23 | But even in such case, it would still be a good idea to isolate private key operations from them considering the impact of private key leaks. 24 | In other words, separating private key operations only to an isolated process in always a good thing to do. 25 | 26 | ### Q. Is there any HTTP server that uses Neverbleed? 27 | 28 | Neverbleed is used by [H2O](https://h2o.examp1e.net/) HTTP2 server since version [1.5.0-beta4](https://github.com/h2o/h2o/releases/tag/v1.5.0-beta4). 29 | 30 | How-to 31 | ------ 32 | 33 | The library exposes two functions: `neverbleed_init` and `neverbleed_load_private_key_file`. 34 | 35 | The first function spawns an external process dedicated to private key operations, and the second function assigns a RSA private key stored in the specified file to an existing SSL context (`SSL_CTX`). 36 | 37 | By 38 | 39 | 1. adding call to `neverbleed_init` 40 | 2. replacing call to `SSL_CTX_use_PrivateKey_file` with `neverbleed_load_private_key_file` 41 | 42 | the privilege separation engine will be used for all the incoming TLS connections. 43 | 44 | ``` 45 | neverbleed_t nb; 46 | char errbuf[NEVERBLEED_ERRBUF_SIZE]; 47 | 48 | /* initialize the OpenSSL library and the neverbleed engine */ 49 | SSL_load_error_strings(); 50 | SSL_library_init(); 51 | OpenSSL_add_all_algorithms(); 52 | if (neverbleed_init(&nb, errbuf) != 0) { 53 | fprintf(stderr, "neverbleed_init failed: %s\n", errbuf); 54 | ... 55 | } 56 | 57 | ... 58 | 59 | /* load certificate chain and private key */ 60 | if (SSL_CTX_use_certificate_chain_file(ssl_ctx, certchain_fn) != 1) { 61 | fprintf(stderr, "failed to load certificate chain file:%s\n", certchain_fn); 62 | ... 63 | } 64 | if (neverbleed_load_private_key_file(&nb, ctx, privkey_fn, errbuf) != 1) { 65 | fprintf(stderr, "failed to load private key from file:%s:%s\n", privkey_fn, errbuf); 66 | ... 67 | } 68 | ``` 69 | 70 | Also, `neverbleed_setuidgid` function can be used to drop the privileges of the daemon process once it completes loading all the private keys. 71 | -------------------------------------------------------------------------------- /neverbleed.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Kazuho Oku, DeNA Co., Ltd. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #if defined(__linux__) 42 | #include 43 | #include 44 | #include 45 | #elif defined(__APPLE__) 46 | #include 47 | #elif defined(__FreeBSD__) 48 | #include 49 | #elif defined(__sun) 50 | #include 51 | #endif 52 | 53 | /* to maximize code-reuse between different stacks, we intentionally use API declared by OpenSSL as legacy */ 54 | #define OPENSSL_SUPPRESS_DEPRECATED 55 | 56 | #include 57 | #include 58 | 59 | #if defined(LIBRESSL_VERSION_NUMBER) ? LIBRESSL_VERSION_NUMBER >= 0x3050000fL : OPENSSL_VERSION_NUMBER >= 0x1010000fL 60 | /* RSA_METHOD is opaque, so RSA_meth* are used. */ 61 | #define NEVERBLEED_OPAQUE_RSA_METHOD 62 | #endif 63 | 64 | #if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_EC) && \ 65 | (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2090100fL) 66 | /* EC_KEY_METHOD and related APIs are avaliable, so ECDSA is enabled. */ 67 | #define NEVERBLEED_ECDSA 68 | #endif 69 | 70 | #include 71 | #ifdef NEVERBLEED_ECDSA 72 | #include 73 | #endif 74 | #include 75 | #include 76 | #include 77 | 78 | #ifdef __linux 79 | #if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) 80 | #define USE_OFFLOAD 1 81 | #endif 82 | #if defined(OPENSSL_IS_BORINGSSL) && defined(NEVERBLEED_BORINGSSL_USE_QAT) 83 | #include "qat_bssl.h" 84 | /* the mapping seems to be missing */ 85 | #ifndef ASYNC_WAIT_CTX_get_all_fds 86 | extern int bssl_async_wait_ctx_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd, size_t *numfds); 87 | #define ASYNC_WAIT_CTX_get_all_fds bssl_async_wait_ctx_get_all_fds 88 | #endif 89 | #define USE_OFFLOAD 1 90 | #endif 91 | #endif 92 | 93 | #if OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) 94 | 95 | static void RSA_get0_key(const RSA *rsa, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) 96 | { 97 | if (n) { 98 | *n = rsa->n; 99 | } 100 | 101 | if (e) { 102 | *e = rsa->e; 103 | } 104 | 105 | if (d) { 106 | *d = rsa->d; 107 | } 108 | } 109 | 110 | static int RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d) 111 | { 112 | if (n == NULL || e == NULL) { 113 | return 0; 114 | } 115 | 116 | BN_free(rsa->n); 117 | BN_free(rsa->e); 118 | BN_free(rsa->d); 119 | rsa->n = n; 120 | rsa->e = e; 121 | rsa->d = d; 122 | 123 | return 1; 124 | } 125 | 126 | static void RSA_set_flags(RSA *r, int flags) 127 | { 128 | r->flags |= flags; 129 | } 130 | 131 | #define EVP_PKEY_up_ref(p) CRYPTO_add(&(p)->references, 1, CRYPTO_LOCK_EVP_PKEY) 132 | 133 | #endif 134 | 135 | #include "neverbleed.h" 136 | 137 | enum neverbleed_type { NEVERBLEED_TYPE_ERROR, NEVERBLEED_TYPE_RSA, NEVERBLEED_TYPE_ECDSA }; 138 | 139 | struct st_neverbleed_rsa_exdata_t { 140 | neverbleed_t *nb; 141 | size_t key_index; 142 | }; 143 | 144 | struct st_neverbleed_thread_data_t { 145 | pid_t self_pid; 146 | int fd; 147 | }; 148 | 149 | /** 150 | * a variant of pthread_once, that does not require you to declare a callback, nor have a global variable 151 | */ 152 | #define NEVERBLEED_MULTITHREAD_ONCE(block) \ 153 | do { \ 154 | static volatile int lock = 0; \ 155 | int lock_loaded = lock; \ 156 | __sync_synchronize(); \ 157 | if (!lock_loaded) { \ 158 | static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; \ 159 | pthread_mutex_lock(&mutex); \ 160 | if (!lock) { \ 161 | do { \ 162 | block \ 163 | } while (0); \ 164 | __sync_synchronize(); \ 165 | lock = 1; \ 166 | } \ 167 | pthread_mutex_unlock(&mutex); \ 168 | } \ 169 | } while (0) 170 | 171 | static void warnvf(const char *fmt, va_list args) 172 | { 173 | char errbuf[256]; 174 | 175 | if (errno != 0) { 176 | strerror_r(errno, errbuf, sizeof(errbuf)); 177 | } else { 178 | errbuf[0] = '\0'; 179 | } 180 | 181 | fprintf(stderr, "[openssl-privsep] "); 182 | vfprintf(stderr, fmt, args); 183 | if (errbuf[0] != '\0') 184 | fputs(errbuf, stderr); 185 | fputc('\n', stderr); 186 | } 187 | 188 | __attribute__((format(printf, 1, 2))) static void warnf(const char *fmt, ...) 189 | { 190 | va_list args; 191 | 192 | va_start(args, fmt); 193 | warnvf(fmt, args); 194 | va_end(args); 195 | } 196 | 197 | __attribute__((format(printf, 1, 2), noreturn)) static void dief(const char *fmt, ...) 198 | { 199 | va_list args; 200 | 201 | va_start(args, fmt); 202 | warnvf(fmt, args); 203 | va_end(args); 204 | 205 | abort(); 206 | } 207 | 208 | static char *dirname(const char *path) 209 | { 210 | const char *last_slash = strrchr(path, '/'); 211 | char *ret; 212 | 213 | if (last_slash == NULL) { 214 | errno = 0; 215 | dief("dirname: no slash in given path:%s", path); 216 | } 217 | if ((ret = malloc(last_slash + 1 - path)) == NULL) 218 | dief("no memory"); 219 | memcpy(ret, path, last_slash - path); 220 | ret[last_slash - path] = '\0'; 221 | return ret; 222 | } 223 | 224 | static void set_cloexec(int fd) 225 | { 226 | if (fcntl(fd, F_SETFD, O_CLOEXEC) == -1) 227 | dief("failed to set O_CLOEXEC to fd %d", fd); 228 | } 229 | 230 | static int read_nbytes(int fd, void *p, size_t sz) 231 | { 232 | while (sz != 0) { 233 | ssize_t r; 234 | while ((r = read(fd, p, sz)) == -1 && errno == EINTR) 235 | ; 236 | if (r == -1) { 237 | return -1; 238 | } else if (r == 0) { 239 | errno = 0; 240 | return -1; 241 | } 242 | p = (char *)p + r; 243 | sz -= r; 244 | } 245 | return 0; 246 | } 247 | 248 | /** 249 | * This function disposes of the memory allocated for `neverbleed_iobuf_t`, but retains the value of `next` and `processing` so that 250 | * the buffer can be "cleared" while in use by worker threads. 251 | */ 252 | static void iobuf_dispose(neverbleed_iobuf_t *buf) 253 | { 254 | if (buf->capacity != 0) 255 | OPENSSL_cleanse(buf->buf, buf->capacity); 256 | free(buf->buf); 257 | buf->buf = NULL; 258 | buf->start = NULL; 259 | buf->end = NULL; 260 | buf->capacity = 0; 261 | } 262 | 263 | static void iobuf_reserve(neverbleed_iobuf_t *buf, size_t extra) 264 | { 265 | size_t start_off, end_off; 266 | 267 | if (extra <= buf->buf - buf->end + buf->capacity) 268 | return; 269 | 270 | if (buf->capacity == 0) 271 | buf->capacity = 4096; 272 | while (buf->buf - buf->end + buf->capacity < extra) 273 | buf->capacity *= 2; 274 | 275 | if (buf->buf != NULL) { 276 | start_off = buf->start - buf->buf; 277 | end_off = buf->end - buf->buf; 278 | } else { 279 | /* C99 forbids us doing `buf->start - buf->buf` when both are NULL (undefined behavior) */ 280 | start_off = 0; 281 | end_off = 0; 282 | } 283 | 284 | if ((buf->buf = realloc(buf->buf, buf->capacity)) == NULL) 285 | dief("realloc failed"); 286 | buf->start = buf->buf + start_off; 287 | buf->end = buf->buf + end_off; 288 | } 289 | 290 | static void iobuf_push_num(neverbleed_iobuf_t *buf, size_t v) 291 | { 292 | iobuf_reserve(buf, sizeof(v)); 293 | memcpy(buf->end, &v, sizeof(v)); 294 | buf->end += sizeof(v); 295 | } 296 | 297 | static void iobuf_push_str(neverbleed_iobuf_t *buf, const char *s) 298 | { 299 | size_t l = strlen(s) + 1; 300 | iobuf_reserve(buf, l); 301 | memcpy(buf->end, s, l); 302 | buf->end += l; 303 | } 304 | 305 | static void iobuf_push_bytes(neverbleed_iobuf_t *buf, const void *p, size_t l) 306 | { 307 | iobuf_push_num(buf, l); 308 | iobuf_reserve(buf, l); 309 | memcpy(buf->end, p, l); 310 | buf->end += l; 311 | } 312 | 313 | static int iobuf_shift_num(neverbleed_iobuf_t *buf, size_t *v) 314 | { 315 | if (neverbleed_iobuf_size(buf) < sizeof(*v)) 316 | return -1; 317 | memcpy(v, buf->start, sizeof(*v)); 318 | buf->start += sizeof(*v); 319 | return 0; 320 | } 321 | 322 | static char *iobuf_shift_str(neverbleed_iobuf_t *buf) 323 | { 324 | char *nul = memchr(buf->start, '\0', neverbleed_iobuf_size(buf)), *ret; 325 | if (nul == NULL) 326 | return NULL; 327 | ret = buf->start; 328 | buf->start = nul + 1; 329 | return ret; 330 | } 331 | 332 | static void *iobuf_shift_bytes(neverbleed_iobuf_t *buf, size_t *l) 333 | { 334 | void *ret; 335 | if (iobuf_shift_num(buf, l) != 0) 336 | return NULL; 337 | if (neverbleed_iobuf_size(buf) < *l) 338 | return NULL; 339 | ret = buf->start; 340 | buf->start += *l; 341 | return ret; 342 | } 343 | 344 | static int iobuf_write(neverbleed_iobuf_t *buf, int fd) 345 | { 346 | struct iovec vecs[2] = {{NULL}}; 347 | size_t bufsz = neverbleed_iobuf_size(buf); 348 | int vecindex; 349 | ssize_t r; 350 | 351 | vecs[0].iov_base = &bufsz; 352 | vecs[0].iov_len = sizeof(bufsz); 353 | vecs[1].iov_base = buf->start; 354 | vecs[1].iov_len = bufsz; 355 | 356 | for (vecindex = 0; vecindex != sizeof(vecs) / sizeof(vecs[0]);) { 357 | while ((r = writev(fd, vecs + vecindex, sizeof(vecs) / sizeof(vecs[0]) - vecindex)) == -1 && errno == EINTR) 358 | ; 359 | if (r == -1) 360 | return -1; 361 | assert(r != 0); 362 | while (r != 0 && r >= vecs[vecindex].iov_len) { 363 | r -= vecs[vecindex].iov_len; 364 | ++vecindex; 365 | } 366 | if (r != 0) { 367 | vecs[vecindex].iov_base = (char *)vecs[vecindex].iov_base + r; 368 | vecs[vecindex].iov_len -= r; 369 | } 370 | } 371 | 372 | return 0; 373 | } 374 | 375 | static int iobuf_read(neverbleed_iobuf_t *buf, int fd) 376 | { 377 | size_t sz; 378 | if (read_nbytes(fd, &sz, sizeof(sz)) != 0) 379 | return -1; 380 | iobuf_reserve(buf, sz); 381 | if (read_nbytes(fd, buf->end, sz) != 0) 382 | return -1; 383 | buf->end += sz; 384 | return 0; 385 | } 386 | 387 | void neverbleed_iobuf_dispose(neverbleed_iobuf_t *buf) 388 | { 389 | iobuf_dispose(buf); 390 | } 391 | 392 | static void iobuf_transaction_write(neverbleed_iobuf_t *buf, struct st_neverbleed_thread_data_t *thdata) 393 | { 394 | if (iobuf_write(buf, thdata->fd) == -1) { 395 | if (errno != 0) { 396 | dief("write error (%d) %s", errno, strerror(errno)); 397 | } else { 398 | dief("connection closed by daemon"); 399 | } 400 | } 401 | } 402 | 403 | static void iobuf_transaction_read(neverbleed_iobuf_t *buf, struct st_neverbleed_thread_data_t *thdata) 404 | { 405 | iobuf_dispose(buf); 406 | if (iobuf_read(buf, thdata->fd) == -1) { 407 | if (errno != 0) { 408 | dief("read error (%d) %s", errno, strerror(errno)); 409 | } else { 410 | dief("connection closed by daemon"); 411 | } 412 | } 413 | } 414 | 415 | /** 416 | * Only sends a request, does not read a response 417 | */ 418 | static void iobuf_transaction_no_response(neverbleed_iobuf_t *buf, struct st_neverbleed_thread_data_t *thdata) 419 | { 420 | if (neverbleed_transaction_cb != NULL) { 421 | neverbleed_transaction_cb(buf, 1); 422 | } else { 423 | iobuf_transaction_write(buf, thdata); 424 | iobuf_dispose(buf); 425 | } 426 | } 427 | 428 | /** 429 | * Sends a request and reads a response. 430 | */ 431 | static void iobuf_transaction(neverbleed_iobuf_t *buf, struct st_neverbleed_thread_data_t *thdata) 432 | { 433 | if (neverbleed_transaction_cb != NULL) { 434 | neverbleed_transaction_cb(buf, 0); 435 | } else { 436 | iobuf_transaction_write(buf, thdata); 437 | iobuf_transaction_read(buf, thdata); 438 | } 439 | } 440 | 441 | #if !defined(NAME_MAX) || defined(__linux__) 442 | /* readdir(3) is known to be thread-safe on Linux and should be thread-safe on a platform that does not have a predefined value for 443 | NAME_MAX */ 444 | #define FOREACH_DIRENT(dp, dent) \ 445 | struct dirent *dent; \ 446 | while ((dent = readdir(dp)) != NULL) 447 | #else 448 | #define FOREACH_DIRENT(dp, dent) \ 449 | struct { \ 450 | struct dirent d; \ 451 | char s[NAME_MAX + 1]; \ 452 | } dent_; \ 453 | struct dirent *dentp, *dent = &dent_.d; \ 454 | int ret; \ 455 | while ((ret = readdir_r(dp, dent, &dentp)) == 0 && dentp != NULL) 456 | #endif /* FOREACH_DIRENT */ 457 | 458 | static void unlink_dir(const char *path) 459 | { 460 | DIR *dp; 461 | char buf[PATH_MAX]; 462 | 463 | if ((dp = opendir(path)) != NULL) { 464 | FOREACH_DIRENT(dp, entp) 465 | { 466 | if (strcmp(entp->d_name, ".") == 0 || strcmp(entp->d_name, "..") == 0) 467 | continue; 468 | snprintf(buf, sizeof(buf), "%s/%s", path, entp->d_name); 469 | unlink_dir(buf); 470 | } 471 | closedir(dp); 472 | } 473 | unlink(path); 474 | rmdir(path); 475 | } 476 | 477 | static void dispose_thread_data(void *_thdata) 478 | { 479 | struct st_neverbleed_thread_data_t *thdata = _thdata; 480 | 481 | assert(thdata->fd >= 0); 482 | close(thdata->fd); 483 | thdata->fd = -1; 484 | free(thdata); 485 | } 486 | 487 | static struct st_neverbleed_thread_data_t *get_thread_data(neverbleed_t *nb) 488 | { 489 | struct st_neverbleed_thread_data_t *thdata; 490 | pid_t self_pid = getpid(); 491 | ssize_t r; 492 | 493 | if ((thdata = pthread_getspecific(nb->thread_key)) != NULL) { 494 | if (thdata->self_pid == self_pid) 495 | return thdata; 496 | /* we have been forked! */ 497 | close(thdata->fd); 498 | } else { 499 | if ((thdata = malloc(sizeof(*thdata))) == NULL) 500 | dief("malloc failed"); 501 | } 502 | 503 | thdata->self_pid = self_pid; 504 | #ifdef SOCK_CLOEXEC 505 | if ((thdata->fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) 506 | dief("socket(2) failed"); 507 | #else 508 | if ((thdata->fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 509 | dief("socket(2) failed"); 510 | set_cloexec(thdata->fd); 511 | #endif 512 | while (connect(thdata->fd, (void *)&nb->sun_, sizeof(nb->sun_)) != 0) 513 | if (errno != EINTR) 514 | dief("failed to connect to privsep daemon"); 515 | while ((r = write(thdata->fd, nb->auth_token, sizeof(nb->auth_token))) == -1 && errno == EINTR) 516 | ; 517 | if (r != sizeof(nb->auth_token)) 518 | dief("failed to send authentication token"); 519 | pthread_setspecific(nb->thread_key, thdata); 520 | 521 | return thdata; 522 | } 523 | 524 | int neverbleed_get_fd(neverbleed_t *nb) 525 | { 526 | struct st_neverbleed_thread_data_t *thdata = get_thread_data(nb); 527 | return thdata->fd; 528 | } 529 | 530 | void neverbleed_transaction_read(neverbleed_t *nb, neverbleed_iobuf_t *buf) 531 | { 532 | struct st_neverbleed_thread_data_t *thdata = get_thread_data(nb); 533 | iobuf_transaction_read(buf, thdata); 534 | } 535 | 536 | void neverbleed_transaction_write(neverbleed_t *nb, neverbleed_iobuf_t *buf) 537 | { 538 | struct st_neverbleed_thread_data_t *thdata = get_thread_data(nb); 539 | iobuf_transaction_write(buf, thdata); 540 | } 541 | 542 | static void do_exdata_free_callback(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) 543 | { 544 | /* when other engines are used, this callback gets called without neverbleed data */ 545 | if (ptr == NULL) 546 | return; 547 | struct st_neverbleed_rsa_exdata_t *exdata = ptr; 548 | struct st_neverbleed_thread_data_t *thdata = get_thread_data(exdata->nb); 549 | 550 | neverbleed_iobuf_t buf = {NULL}; 551 | iobuf_push_str(&buf, "del_pkey"); 552 | iobuf_push_num(&buf, exdata->key_index); 553 | // "del_pkey" command is fire-and-forget, it cannot fail, so doesn't have a response 554 | iobuf_transaction_no_response(&buf, thdata); 555 | 556 | free(exdata); 557 | } 558 | 559 | static int get_rsa_exdata_idx(void); 560 | static void rsa_exdata_free_callback(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) 561 | { 562 | assert(idx == get_rsa_exdata_idx()); 563 | do_exdata_free_callback(parent, ptr, ad, idx, argl, argp); 564 | } 565 | 566 | static int get_rsa_exdata_idx(void) 567 | { 568 | static volatile int index; 569 | NEVERBLEED_MULTITHREAD_ONCE({ 570 | index = RSA_get_ex_new_index(0, NULL, NULL, NULL, rsa_exdata_free_callback); 571 | }); 572 | return index; 573 | } 574 | static void get_privsep_data(const RSA *rsa, struct st_neverbleed_rsa_exdata_t **exdata, 575 | struct st_neverbleed_thread_data_t **thdata) 576 | { 577 | *exdata = RSA_get_ex_data(rsa, get_rsa_exdata_idx()); 578 | if (*exdata == NULL) { 579 | errno = 0; 580 | dief("invalid internal ref"); 581 | } 582 | *thdata = get_thread_data((*exdata)->nb); 583 | } 584 | 585 | static struct { 586 | struct { 587 | pthread_mutex_t lock; 588 | /** 589 | * if the slot is use contains a non-NULL key; if not in use, contains the index of the next empty slot or SIZE_MAX if there 590 | * are no more empty slots 591 | */ 592 | union { 593 | EVP_PKEY *pkey; 594 | size_t next_empty; 595 | } *slots; 596 | size_t num_slots; 597 | size_t first_empty; 598 | } keys; 599 | neverbleed_t *nb; 600 | } daemon_vars = {{.lock = PTHREAD_MUTEX_INITIALIZER, .first_empty = SIZE_MAX}}; 601 | 602 | static __thread struct { 603 | int sockfd; 604 | #ifdef __linux 605 | int epollfd; 606 | #endif 607 | struct { 608 | neverbleed_iobuf_t *first, **next; 609 | } responses; 610 | } conn_ctx; 611 | 612 | static int use_offload = 0; 613 | 614 | #if USE_OFFLOAD 615 | 616 | struct engine_request { 617 | neverbleed_iobuf_t *buf; 618 | int async_fd; 619 | #ifdef OPENSSL_IS_BORINGSSL 620 | struct { 621 | RSA *rsa; 622 | uint8_t output[512]; 623 | union { 624 | struct { 625 | uint8_t padded[512]; 626 | } digestsign; 627 | }; 628 | } data; 629 | async_ctx *async_ctx; 630 | #else 631 | int (*stub)(neverbleed_iobuf_t *); 632 | struct { 633 | ASYNC_WAIT_CTX *ctx; 634 | ASYNC_JOB *job; 635 | } async; 636 | #endif 637 | }; 638 | 639 | static void offload_free_request(struct engine_request *req) 640 | { 641 | #ifdef OPENSSL_IS_BORINGSSL 642 | bssl_qat_async_finish_job(req->async_ctx); 643 | RSA_free(req->data.rsa); 644 | #else 645 | ASYNC_WAIT_CTX_free(req->async.ctx); 646 | #endif 647 | OPENSSL_cleanse(req, sizeof(*req)); 648 | free(req); 649 | } 650 | 651 | static int do_epoll_ctl(int epollfd, int op, int fd, struct epoll_event *event) 652 | { 653 | int ret; 654 | while ((ret = epoll_ctl(epollfd, op, fd, event) != 0) && errno == EINTR) 655 | ; 656 | return ret; 657 | } 658 | 659 | static void register_wait_fd(struct engine_request *req) 660 | { 661 | #ifdef OPENSSL_IS_BORINGSSL 662 | ASYNC_WAIT_CTX *ctx = req->async_ctx->currjob->waitctx; 663 | #else 664 | ASYNC_WAIT_CTX *ctx = req->async.ctx; 665 | #endif 666 | size_t numfds; 667 | 668 | if (!ASYNC_WAIT_CTX_get_all_fds(ctx, NULL, &numfds) || numfds != 1) 669 | dief("unexpected number of fds (%zu) requested in async mode\n", numfds); 670 | if (!ASYNC_WAIT_CTX_get_all_fds(ctx, &req->async_fd, &numfds)) 671 | dief("ASYNC_WAIT_CTX_get_all_fds failed\n"); 672 | struct epoll_event ev = {.events = EPOLLIN, .data.ptr = req}; 673 | if (do_epoll_ctl(conn_ctx.epollfd, EPOLL_CTL_ADD, req->async_fd, &ev) != 0) 674 | dief("epoll_ctl failed:%d\n", errno); 675 | } 676 | 677 | #endif 678 | 679 | static int send_responses(int cleanup) 680 | { 681 | neverbleed_iobuf_t *buf; 682 | int result = 0; 683 | 684 | /* Send all buffers that have data being filled. The lock is held until everything is being done, as this function can be called 685 | * from multiple threads simultaneously. */ 686 | while ((buf = conn_ctx.responses.first) != NULL && !buf->processing) { 687 | if ((conn_ctx.responses.first = buf->next) == NULL) 688 | conn_ctx.responses.next = &conn_ctx.responses.first; 689 | if (!cleanup && iobuf_write(buf, conn_ctx.sockfd) != 0) { 690 | warnf(errno != 0 ? "write error" : "connection closed by client"); 691 | result = -1; 692 | } 693 | iobuf_dispose(buf); 694 | free(buf); 695 | if (result != 0) 696 | break; 697 | } 698 | 699 | return result; 700 | } 701 | 702 | static RSA *daemon_get_rsa(size_t key_index) 703 | { 704 | RSA *rsa = NULL; 705 | 706 | pthread_mutex_lock(&daemon_vars.keys.lock); 707 | if (key_index < daemon_vars.keys.num_slots) 708 | rsa = EVP_PKEY_get1_RSA(daemon_vars.keys.slots[key_index].pkey); 709 | pthread_mutex_unlock(&daemon_vars.keys.lock); 710 | 711 | return rsa; 712 | } 713 | 714 | size_t allocate_slot(void) 715 | { 716 | /* expand if all slots are in use */ 717 | if (daemon_vars.keys.first_empty == SIZE_MAX) { 718 | size_t new_capacity = (daemon_vars.keys.num_slots < 4 ? 4 : daemon_vars.keys.num_slots) * 2; 719 | if ((daemon_vars.keys.slots = realloc(daemon_vars.keys.slots, sizeof(daemon_vars.keys.slots[0]) * new_capacity)) == NULL) 720 | dief("no memory"); 721 | daemon_vars.keys.first_empty = daemon_vars.keys.num_slots; 722 | for (size_t i = daemon_vars.keys.num_slots; i < new_capacity - 1; ++i) 723 | daemon_vars.keys.slots[i].next_empty = i + 1; 724 | daemon_vars.keys.slots[new_capacity - 1].next_empty = SIZE_MAX; 725 | daemon_vars.keys.num_slots = new_capacity; 726 | } 727 | 728 | /* detach the first empty slot from the empty list */ 729 | size_t slot_index = daemon_vars.keys.first_empty; 730 | daemon_vars.keys.first_empty = daemon_vars.keys.slots[slot_index].next_empty; 731 | 732 | /* set bogus value in the allocated slot to help figure out what happened upon crash */ 733 | daemon_vars.keys.slots[slot_index].next_empty = SIZE_MAX - 1; 734 | 735 | return slot_index; 736 | } 737 | 738 | static size_t daemon_set_pkey(EVP_PKEY *pkey) 739 | { 740 | assert(pkey != NULL); 741 | 742 | pthread_mutex_lock(&daemon_vars.keys.lock); 743 | 744 | size_t index = allocate_slot(); 745 | daemon_vars.keys.slots[index].pkey = pkey; 746 | EVP_PKEY_up_ref(pkey); 747 | 748 | pthread_mutex_unlock(&daemon_vars.keys.lock); 749 | 750 | return index; 751 | } 752 | 753 | static int priv_encdec_proxy(const char *cmd, int flen, const unsigned char *from, unsigned char *_to, RSA *rsa, int padding) 754 | { 755 | struct st_neverbleed_rsa_exdata_t *exdata; 756 | struct st_neverbleed_thread_data_t *thdata; 757 | neverbleed_iobuf_t buf = {NULL}; 758 | size_t ret; 759 | unsigned char *to; 760 | size_t tolen; 761 | 762 | get_privsep_data(rsa, &exdata, &thdata); 763 | 764 | iobuf_push_str(&buf, cmd); 765 | iobuf_push_bytes(&buf, from, flen); 766 | iobuf_push_num(&buf, exdata->key_index); 767 | iobuf_push_num(&buf, padding); 768 | 769 | iobuf_transaction(&buf, thdata); 770 | 771 | if (iobuf_shift_num(&buf, &ret) != 0 || (to = iobuf_shift_bytes(&buf, &tolen)) == NULL) { 772 | errno = 0; 773 | dief("failed to parse response"); 774 | } 775 | memcpy(_to, to, tolen); 776 | iobuf_dispose(&buf); 777 | 778 | return (int)ret; 779 | } 780 | 781 | static int priv_encdec_stub(const char *name, 782 | int (*func)(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding), 783 | neverbleed_iobuf_t *buf) 784 | { 785 | unsigned char *from, to[4096]; 786 | size_t flen; 787 | size_t key_index, padding; 788 | RSA *rsa; 789 | int ret; 790 | 791 | if ((from = iobuf_shift_bytes(buf, &flen)) == NULL || iobuf_shift_num(buf, &key_index) != 0 || 792 | iobuf_shift_num(buf, &padding) != 0) { 793 | errno = 0; 794 | warnf("%s: failed to parse request", name); 795 | return -1; 796 | } 797 | if ((rsa = daemon_get_rsa(key_index)) == NULL) { 798 | errno = 0; 799 | warnf("%s: invalid key index:%zu\n", name, key_index); 800 | return -1; 801 | } 802 | ret = func((int)flen, from, to, rsa, (int)padding); 803 | iobuf_dispose(buf); 804 | RSA_free(rsa); 805 | 806 | iobuf_push_num(buf, ret); 807 | iobuf_push_bytes(buf, to, ret > 0 ? ret : 0); 808 | 809 | return 0; 810 | } 811 | 812 | #if !defined(OPENSSL_IS_BORINGSSL) 813 | 814 | static int priv_enc_proxy(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) 815 | { 816 | return priv_encdec_proxy("priv_enc", flen, from, to, rsa, padding); 817 | } 818 | 819 | static int priv_enc_stub(neverbleed_iobuf_t *buf) 820 | { 821 | return priv_encdec_stub(__FUNCTION__, RSA_private_encrypt, buf); 822 | } 823 | 824 | static int priv_dec_proxy(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) 825 | { 826 | return priv_encdec_proxy("priv_dec", flen, from, to, rsa, padding); 827 | } 828 | 829 | static int priv_dec_stub(neverbleed_iobuf_t *buf) 830 | { 831 | return priv_encdec_stub(__FUNCTION__, RSA_private_decrypt, buf); 832 | } 833 | 834 | static int sign_proxy(int type, const unsigned char *m, unsigned int m_len, unsigned char *_sigret, unsigned *_siglen, 835 | const RSA *rsa) 836 | { 837 | struct st_neverbleed_rsa_exdata_t *exdata; 838 | struct st_neverbleed_thread_data_t *thdata; 839 | neverbleed_iobuf_t buf = {NULL}; 840 | size_t ret, siglen; 841 | unsigned char *sigret; 842 | 843 | get_privsep_data(rsa, &exdata, &thdata); 844 | 845 | iobuf_push_str(&buf, "sign"); 846 | iobuf_push_num(&buf, type); 847 | iobuf_push_bytes(&buf, m, m_len); 848 | iobuf_push_num(&buf, exdata->key_index); 849 | iobuf_transaction(&buf, thdata); 850 | 851 | if (iobuf_shift_num(&buf, &ret) != 0 || (sigret = iobuf_shift_bytes(&buf, &siglen)) == NULL) { 852 | errno = 0; 853 | dief("failed to parse response"); 854 | } 855 | memcpy(_sigret, sigret, siglen); 856 | *_siglen = (unsigned)siglen; 857 | iobuf_dispose(&buf); 858 | 859 | return (int)ret; 860 | } 861 | 862 | static int sign_stub(neverbleed_iobuf_t *buf) 863 | { 864 | unsigned char *m, sigret[4096]; 865 | size_t type, m_len, key_index; 866 | RSA *rsa; 867 | unsigned siglen = 0; 868 | int ret; 869 | 870 | if (iobuf_shift_num(buf, &type) != 0 || (m = iobuf_shift_bytes(buf, &m_len)) == NULL || iobuf_shift_num(buf, &key_index) != 0) { 871 | errno = 0; 872 | warnf("%s: failed to parse request", __FUNCTION__); 873 | return -1; 874 | } 875 | if ((rsa = daemon_get_rsa(key_index)) == NULL) { 876 | errno = 0; 877 | warnf("%s: invalid key index:%zu", __FUNCTION__, key_index); 878 | return -1; 879 | } 880 | ret = RSA_sign((int)type, m, (unsigned)m_len, sigret, &siglen, rsa); 881 | iobuf_dispose(buf); 882 | RSA_free(rsa); 883 | 884 | iobuf_push_num(buf, ret); 885 | iobuf_push_bytes(buf, sigret, ret == 1 ? siglen : 0); 886 | 887 | return 0; 888 | } 889 | 890 | #endif 891 | 892 | static EVP_PKEY *create_pkey(neverbleed_t *nb, size_t key_index, const char *ebuf, const char *nbuf) 893 | { 894 | struct st_neverbleed_rsa_exdata_t *exdata; 895 | RSA *rsa; 896 | EVP_PKEY *pkey; 897 | BIGNUM *e = NULL, *n = NULL; 898 | 899 | if ((exdata = malloc(sizeof(*exdata))) == NULL) { 900 | fprintf(stderr, "no memory\n"); 901 | abort(); 902 | } 903 | exdata->nb = nb; 904 | exdata->key_index = key_index; 905 | 906 | rsa = RSA_new_method(nb->engine); 907 | RSA_set_ex_data(rsa, get_rsa_exdata_idx(), exdata); 908 | if (BN_hex2bn(&e, ebuf) == 0) { 909 | fprintf(stderr, "failed to parse e:%s\n", ebuf); 910 | abort(); 911 | } 912 | if (BN_hex2bn(&n, nbuf) == 0) { 913 | fprintf(stderr, "failed to parse n:%s\n", nbuf); 914 | abort(); 915 | } 916 | RSA_set0_key(rsa, n, e, NULL); 917 | #if !defined(OPENSSL_IS_BORINGSSL) 918 | RSA_set_flags(rsa, RSA_FLAG_EXT_PKEY); 919 | #endif 920 | 921 | pkey = EVP_PKEY_new(); 922 | EVP_PKEY_set1_RSA(pkey, rsa); 923 | RSA_free(rsa); 924 | 925 | return pkey; 926 | } 927 | 928 | #ifdef NEVERBLEED_ECDSA 929 | 930 | static EC_KEY *daemon_get_ecdsa(size_t key_index) 931 | { 932 | EC_KEY *ec_key = NULL; 933 | 934 | pthread_mutex_lock(&daemon_vars.keys.lock); 935 | if (key_index < daemon_vars.keys.num_slots) 936 | ec_key = EVP_PKEY_get1_EC_KEY(daemon_vars.keys.slots[key_index].pkey); 937 | pthread_mutex_unlock(&daemon_vars.keys.lock); 938 | 939 | return ec_key; 940 | } 941 | 942 | static int ecdsa_sign_stub(neverbleed_iobuf_t *buf) 943 | { 944 | unsigned char *m, sigret[4096]; 945 | size_t type, m_len, key_index; 946 | EC_KEY *ec_key; 947 | unsigned siglen = 0; 948 | int ret; 949 | 950 | if (iobuf_shift_num(buf, &type) != 0 || (m = iobuf_shift_bytes(buf, &m_len)) == NULL || iobuf_shift_num(buf, &key_index) != 0) { 951 | errno = 0; 952 | warnf("%s: failed to parse request", __FUNCTION__); 953 | return -1; 954 | } 955 | if ((ec_key = daemon_get_ecdsa(key_index)) == NULL) { 956 | errno = 0; 957 | warnf("%s: invalid key index:%zu", __FUNCTION__, key_index); 958 | return -1; 959 | } 960 | 961 | ret = ECDSA_sign((int)type, m, (unsigned)m_len, sigret, &siglen, ec_key); 962 | iobuf_dispose(buf); 963 | 964 | EC_KEY_free(ec_key); 965 | 966 | iobuf_push_num(buf, ret); 967 | iobuf_push_bytes(buf, sigret, ret == 1 ? siglen : 0); 968 | 969 | return 0; 970 | } 971 | 972 | static int get_ecdsa_exdata_idx(void); 973 | static void ecdsa_exdata_free_callback(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) 974 | { 975 | assert(idx == get_ecdsa_exdata_idx()); 976 | do_exdata_free_callback(parent, ptr, ad, idx, argl, argp); 977 | } 978 | 979 | static int get_ecdsa_exdata_idx(void) 980 | { 981 | static volatile int index; 982 | NEVERBLEED_MULTITHREAD_ONCE({ 983 | index = EC_KEY_get_ex_new_index(0, NULL, NULL, NULL, ecdsa_exdata_free_callback); 984 | }); 985 | return index; 986 | } 987 | 988 | static void ecdsa_get_privsep_data(const EC_KEY *ec_key, struct st_neverbleed_rsa_exdata_t **exdata, 989 | struct st_neverbleed_thread_data_t **thdata) 990 | { 991 | *exdata = EC_KEY_get_ex_data(ec_key, get_ecdsa_exdata_idx()); 992 | if (*exdata == NULL) { 993 | errno = 0; 994 | dief("invalid internal ref"); 995 | } 996 | *thdata = get_thread_data((*exdata)->nb); 997 | } 998 | 999 | static int ecdsa_sign_proxy(int type, const unsigned char *m, int m_len, unsigned char *_sigret, unsigned int *_siglen, 1000 | const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *ec_key) 1001 | { 1002 | struct st_neverbleed_rsa_exdata_t *exdata; 1003 | struct st_neverbleed_thread_data_t *thdata; 1004 | neverbleed_iobuf_t buf = {NULL}; 1005 | size_t ret, siglen; 1006 | unsigned char *sigret; 1007 | 1008 | ecdsa_get_privsep_data(ec_key, &exdata, &thdata); 1009 | 1010 | /* as far as I've tested so far, kinv and rp are always NULL. 1011 | Looks like setup_sign will precompute this, but it is only 1012 | called sign_sig, and it seems to be not used in TLS ECDSA */ 1013 | if (kinv != NULL || rp != NULL) { 1014 | errno = 0; 1015 | dief("unexpected non-NULL kinv and rp"); 1016 | } 1017 | 1018 | iobuf_push_str(&buf, "ecdsa_sign"); 1019 | iobuf_push_num(&buf, type); 1020 | iobuf_push_bytes(&buf, m, m_len); 1021 | iobuf_push_num(&buf, exdata->key_index); 1022 | iobuf_transaction(&buf, thdata); 1023 | 1024 | if (iobuf_shift_num(&buf, &ret) != 0 || (sigret = iobuf_shift_bytes(&buf, &siglen)) == NULL) { 1025 | errno = 0; 1026 | dief("failed to parse response"); 1027 | } 1028 | memcpy(_sigret, sigret, siglen); 1029 | *_siglen = (unsigned)siglen; 1030 | iobuf_dispose(&buf); 1031 | 1032 | return (int)ret; 1033 | } 1034 | 1035 | static EVP_PKEY *ecdsa_create_pkey(neverbleed_t *nb, size_t key_index, int curve_name, const void *pubkey, size_t pubkey_len) 1036 | { 1037 | struct st_neverbleed_rsa_exdata_t *exdata; 1038 | EC_KEY *ec_key; 1039 | EC_GROUP *ec_group; 1040 | EC_POINT *ec_pubkey; 1041 | EVP_PKEY *pkey; 1042 | 1043 | if ((exdata = malloc(sizeof(*exdata))) == NULL) { 1044 | fprintf(stderr, "no memory\n"); 1045 | abort(); 1046 | } 1047 | exdata->nb = nb; 1048 | exdata->key_index = key_index; 1049 | 1050 | ec_key = EC_KEY_new_method(nb->engine); 1051 | EC_KEY_set_ex_data(ec_key, get_ecdsa_exdata_idx(), exdata); 1052 | 1053 | ec_group = EC_GROUP_new_by_curve_name(curve_name); 1054 | if (!ec_group) { 1055 | fprintf(stderr, "could not create EC_GROUP\n"); 1056 | abort(); 1057 | } 1058 | 1059 | EC_KEY_set_group(ec_key, ec_group); 1060 | 1061 | ec_pubkey = EC_POINT_new(ec_group); 1062 | assert(ec_pubkey != NULL); 1063 | if (!EC_POINT_oct2point(ec_group, ec_pubkey, pubkey, pubkey_len, NULL)) { 1064 | fprintf(stderr, "failed to get ECDSA ephemeral public key from BIGNUM\n"); 1065 | abort(); 1066 | } 1067 | EC_KEY_set_public_key(ec_key, ec_pubkey); 1068 | 1069 | pkey = EVP_PKEY_new(); 1070 | EVP_PKEY_set1_EC_KEY(pkey, ec_key); 1071 | 1072 | EC_POINT_free(ec_pubkey); 1073 | EC_GROUP_free(ec_group); 1074 | EC_KEY_free(ec_key); 1075 | 1076 | return pkey; 1077 | } 1078 | 1079 | #endif 1080 | 1081 | static EVP_PKEY *daemon_get_pkey(size_t key_index) 1082 | { 1083 | EVP_PKEY *pkey = NULL; 1084 | 1085 | pthread_mutex_lock(&daemon_vars.keys.lock); 1086 | if (key_index < daemon_vars.keys.num_slots) { 1087 | pkey = daemon_vars.keys.slots[key_index].pkey; 1088 | EVP_PKEY_up_ref(pkey); 1089 | } 1090 | pthread_mutex_unlock(&daemon_vars.keys.lock); 1091 | 1092 | return pkey; 1093 | } 1094 | 1095 | #if USE_OFFLOAD && defined(OPENSSL_IS_BORINGSSL) 1096 | 1097 | static struct engine_request *bssl_offload_create_request(neverbleed_iobuf_t *buf, EVP_PKEY *pkey) 1098 | { 1099 | RSA *_rsa = EVP_PKEY_get1_RSA(pkey); 1100 | 1101 | struct engine_request *req = malloc(sizeof(*req)); 1102 | if (req == NULL) 1103 | dief("no memory\n"); 1104 | *req = (struct engine_request){.buf = buf, .async_fd = -1, .async_ctx = bssl_qat_async_start_job(), .data.rsa = _rsa}; 1105 | 1106 | if (req->async_ctx == NULL) 1107 | dief("failed to initialize async job\n"); 1108 | if (RSA_size(req->data.rsa) > sizeof(req->data.output)) 1109 | dief("RSA key too large\n"); 1110 | 1111 | return req; 1112 | } 1113 | 1114 | static void bssl_offload_digestsign(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const EVP_MD *md, const void *signdata, size_t signlen, 1115 | int rsa_pss) 1116 | { 1117 | uint8_t digest[EVP_MAX_MD_SIZE]; 1118 | unsigned digestlen; 1119 | 1120 | { /* generate digest of signdata */ 1121 | EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); 1122 | if (mdctx == NULL) 1123 | dief("no memory\n"); 1124 | if (!EVP_DigestInit_ex(mdctx, md, NULL) || !EVP_DigestUpdate(mdctx, signdata, signlen) || 1125 | !EVP_DigestFinal_ex(mdctx, digest, &digestlen)) 1126 | dief("digest calculation failed\n"); 1127 | EVP_MD_CTX_free(mdctx); 1128 | } 1129 | 1130 | struct engine_request *req = bssl_offload_create_request(buf, pkey); 1131 | size_t rsa_size = RSA_size(req->data.rsa), padded_len; 1132 | int padding; 1133 | 1134 | /* generate padded octets to be signed */ 1135 | if (rsa_pss) { 1136 | if (!RSA_padding_add_PKCS1_PSS_mgf1(req->data.rsa, req->data.digestsign.padded, digest, md, md, -1)) 1137 | dief("RSA_paddding_add_PKCS1_PSS_mgf1 failed\n"); 1138 | padded_len = rsa_size; 1139 | padding = RSA_NO_PADDING; 1140 | } else { 1141 | /* PKCS1 padding */ 1142 | int hash_nid = EVP_MD_type(md), is_alloced; 1143 | uint8_t *tbs; 1144 | if (!RSA_add_pkcs1_prefix(&tbs, &padded_len, &is_alloced, hash_nid, digest, digestlen)) 1145 | dief("RSA_add_pkcs1_prefix failed\n"); 1146 | if (padded_len > rsa_size) 1147 | dief("output of RSA_add_pkcs1_prefix is unexpectedly large\n"); 1148 | memcpy(req->data.digestsign.padded, tbs, padded_len); 1149 | if (is_alloced) 1150 | OPENSSL_free(tbs); 1151 | padding = RSA_PKCS1_PADDING; 1152 | } 1153 | 1154 | OPENSSL_cleanse(digest, sizeof(digest)); 1155 | 1156 | /* dispatch RSA calculation */ 1157 | RSA_METHOD *meth = bssl_engine_get_rsa_method(); 1158 | if (meth == NULL) 1159 | dief("failed to obtain QAT RSA method table\n"); 1160 | size_t siglen; 1161 | if (!meth->sign_raw(req->data.rsa, &siglen, req->data.output, rsa_size, req->data.digestsign.padded, padded_len, padding)) 1162 | dief("sign_raw failure\n"); 1163 | if (siglen != 0) 1164 | dief("sign_raw completed synchronously unexpectedly\n"); 1165 | 1166 | buf->processing = 1; 1167 | register_wait_fd(req); 1168 | } 1169 | 1170 | static int bssl_offload_decrypt(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const void *src, size_t len) 1171 | { 1172 | struct engine_request *req = bssl_offload_create_request(buf, pkey); 1173 | 1174 | /* dispatch RSA calculation */ 1175 | RSA_METHOD *meth = bssl_engine_get_rsa_method(); 1176 | if (meth == NULL) 1177 | dief("failed to obtain QAT RSA method table\n"); 1178 | size_t outlen; 1179 | if (!meth->decrypt(req->data.rsa, &outlen, req->data.output, sizeof(req->data.output), src, len, RSA_NO_PADDING)) { 1180 | warnf("RSA decrypt failure\n"); 1181 | goto Exit; 1182 | } 1183 | if (outlen != 0) 1184 | dief("RSA decrypt completed synchronously unexpectedly\n"); 1185 | 1186 | buf->processing = 1; 1187 | register_wait_fd(req); 1188 | return 1; 1189 | 1190 | Exit: 1191 | offload_free_request(req); 1192 | return 0; 1193 | } 1194 | 1195 | #endif 1196 | 1197 | static int digestsign_stub(neverbleed_iobuf_t *buf) 1198 | { 1199 | size_t key_index, md_nid, signlen; 1200 | void *signdata; 1201 | size_t rsa_pss; 1202 | EVP_PKEY *pkey; 1203 | const EVP_MD *md; 1204 | 1205 | /* parse input */ 1206 | if (iobuf_shift_num(buf, &key_index) != 0 || iobuf_shift_num(buf, &md_nid) != 0 || 1207 | (signdata = iobuf_shift_bytes(buf, &signlen)) == NULL || iobuf_shift_num(buf, &rsa_pss) != 0) { 1208 | errno = 0; 1209 | warnf("%s: failed to parse request", __FUNCTION__); 1210 | return -1; 1211 | } 1212 | if ((pkey = daemon_get_pkey(key_index)) == NULL) { 1213 | errno = 0; 1214 | warnf("%s: invalid key index:%zu", __FUNCTION__, key_index); 1215 | return -1; 1216 | } 1217 | if (md_nid != SIZE_MAX) { 1218 | if ((md = EVP_get_digestbynid((int)md_nid)) == NULL) { 1219 | errno = 0; 1220 | warnf("%s: invalid EVP_MD nid", __FUNCTION__); 1221 | return -1; 1222 | } 1223 | } else { 1224 | md = NULL; 1225 | } 1226 | 1227 | #if USE_OFFLOAD && defined(OPENSSL_IS_BORINGSSL) 1228 | if (use_offload && EVP_PKEY_id(pkey) == EVP_PKEY_RSA) { 1229 | bssl_offload_digestsign(buf, pkey, md, signdata, signlen, rsa_pss); 1230 | goto Exit; 1231 | } 1232 | #endif 1233 | 1234 | /* generate signature */ 1235 | EVP_MD_CTX *mdctx = NULL; 1236 | EVP_PKEY_CTX *pkey_ctx = NULL; 1237 | unsigned char digestbuf[4096]; 1238 | size_t digestlen; 1239 | 1240 | if ((mdctx = EVP_MD_CTX_create()) == NULL) 1241 | goto Softfail; 1242 | if (EVP_DigestSignInit(mdctx, &pkey_ctx, md, NULL, pkey) != 1) 1243 | goto Softfail; 1244 | if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && rsa_pss) { 1245 | if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1 || 1246 | EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) != 1) 1247 | goto Softfail; 1248 | if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, md) != 1) 1249 | goto Softfail; 1250 | } 1251 | /* ED25519 keys can never be loaded, so use the Update -> Final call chain without worrying about backward compatibility */ 1252 | if (EVP_DigestSignUpdate(mdctx, signdata, signlen) != 1) 1253 | goto Softfail; 1254 | if (EVP_DigestSignFinal(mdctx, NULL, &digestlen) != 1) 1255 | goto Softfail; 1256 | if (sizeof(digestbuf) < digestlen) { 1257 | warnf("%s: digest unexpectedly long as %zu bytes", __FUNCTION__, digestlen); 1258 | goto Softfail; 1259 | } 1260 | if (EVP_DigestSignFinal(mdctx, digestbuf, &digestlen) != 1) 1261 | goto Softfail; 1262 | 1263 | Respond: /* build response */ 1264 | iobuf_dispose(buf); 1265 | iobuf_push_bytes(buf, digestbuf, digestlen); 1266 | if (mdctx != NULL) 1267 | EVP_MD_CTX_destroy(mdctx); 1268 | Exit: 1269 | if (pkey != NULL) 1270 | EVP_PKEY_free(pkey); 1271 | return 0; 1272 | 1273 | Softfail: 1274 | digestlen = 0; 1275 | goto Respond; 1276 | } 1277 | 1278 | void neverbleed_start_digestsign(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const EVP_MD *md, const void *input, size_t len, 1279 | int rsa_pss) 1280 | { 1281 | struct st_neverbleed_rsa_exdata_t *exdata; 1282 | struct st_neverbleed_thread_data_t *thdata; 1283 | const char *cmd = "digestsign"; 1284 | 1285 | /* obtain reference */ 1286 | switch (EVP_PKEY_base_id(pkey)) { 1287 | case EVP_PKEY_RSA: { 1288 | RSA *rsa = EVP_PKEY_get1_RSA(pkey); /* get0 is available not available in OpenSSL 1.0.2 */ 1289 | get_privsep_data(rsa, &exdata, &thdata); 1290 | RSA_free(rsa); 1291 | cmd = "digestsign-rsa"; 1292 | } break; 1293 | #ifdef NEVERBLEED_ECDSA 1294 | case EVP_PKEY_EC: 1295 | ecdsa_get_privsep_data(EVP_PKEY_get0_EC_KEY(pkey), &exdata, &thdata); 1296 | break; 1297 | #endif 1298 | default: 1299 | dief("unexpected private key"); 1300 | break; 1301 | } 1302 | 1303 | *buf = (neverbleed_iobuf_t){NULL}; 1304 | iobuf_push_str(buf, cmd); 1305 | iobuf_push_num(buf, exdata->key_index); 1306 | iobuf_push_num(buf, md != NULL ? (size_t)EVP_MD_nid(md) : SIZE_MAX); 1307 | iobuf_push_bytes(buf, input, len); 1308 | iobuf_push_num(buf, rsa_pss); 1309 | } 1310 | 1311 | void neverbleed_finish_digestsign(neverbleed_iobuf_t *buf, void **digest, size_t *digest_len) 1312 | { 1313 | const void *src; 1314 | 1315 | if ((src = iobuf_shift_bytes(buf, digest_len)) == NULL) { 1316 | errno = 0; 1317 | dief("failed to parse response"); 1318 | } 1319 | if ((*digest = malloc(*digest_len)) == NULL) 1320 | dief("no memory"); 1321 | memcpy(*digest, src, *digest_len); 1322 | 1323 | iobuf_dispose(buf); 1324 | } 1325 | 1326 | static int decrypt_stub(neverbleed_iobuf_t *buf) 1327 | { 1328 | size_t key_index, srclen; 1329 | void *src; 1330 | EVP_PKEY *pkey; 1331 | RSA *rsa; 1332 | uint8_t decryptbuf[1024]; 1333 | int decryptlen; 1334 | 1335 | /* parse input */ 1336 | if (iobuf_shift_num(buf, &key_index) != 0 || (src = iobuf_shift_bytes(buf, &srclen)) == NULL) { 1337 | errno = 0; 1338 | warnf("%s: failed to parse request", __FUNCTION__); 1339 | return -1; 1340 | } 1341 | if ((pkey = daemon_get_pkey(key_index)) == NULL) { 1342 | errno = 0; 1343 | warnf("%s: invalid key index:%zu", __FUNCTION__, key_index); 1344 | return -1; 1345 | } 1346 | 1347 | rsa = EVP_PKEY_get1_RSA(pkey); /* get0 is available not available in OpenSSL 1.0.2 */ 1348 | assert(rsa != NULL); 1349 | assert(sizeof(decryptbuf) >= RSA_size(rsa)); 1350 | 1351 | #if USE_OFFLOAD && defined(OPENSSL_IS_BORINGSSL) 1352 | if (use_offload) { 1353 | if (!bssl_offload_decrypt(buf, pkey, src, srclen)) 1354 | goto Softfail; 1355 | 1356 | goto Exit; 1357 | } 1358 | #endif 1359 | 1360 | if ((decryptlen = RSA_private_decrypt(srclen, src, decryptbuf, rsa, RSA_NO_PADDING)) == -1) { 1361 | errno = 0; 1362 | warnf("RSA decryption error"); 1363 | goto Softfail; 1364 | } 1365 | 1366 | Respond: 1367 | iobuf_dispose(buf); 1368 | iobuf_push_bytes(buf, decryptbuf, decryptlen); 1369 | Exit: 1370 | RSA_free(rsa); 1371 | EVP_PKEY_free(pkey); 1372 | return 0; 1373 | 1374 | Softfail: 1375 | decryptlen = 0; 1376 | goto Respond; 1377 | } 1378 | 1379 | void neverbleed_start_decrypt(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const void *input, size_t len) 1380 | { 1381 | struct st_neverbleed_rsa_exdata_t *exdata; 1382 | struct st_neverbleed_thread_data_t *thdata; 1383 | 1384 | { 1385 | RSA *rsa = EVP_PKEY_get1_RSA(pkey); /* get0 is available not available in OpenSSL 1.0.2 */ 1386 | assert(rsa != NULL); 1387 | get_privsep_data(rsa, &exdata, &thdata); 1388 | RSA_free(rsa); 1389 | } 1390 | 1391 | *buf = (neverbleed_iobuf_t){NULL}; 1392 | iobuf_push_str(buf, "decrypt"); 1393 | iobuf_push_num(buf, exdata->key_index); 1394 | iobuf_push_bytes(buf, input, len); 1395 | } 1396 | 1397 | void neverbleed_finish_decrypt(neverbleed_iobuf_t *buf, void **digest, size_t *digest_len) 1398 | { 1399 | neverbleed_finish_digestsign(buf, digest, digest_len); 1400 | } 1401 | 1402 | int neverbleed_load_private_key_file(neverbleed_t *nb, SSL_CTX *ctx, const char *fn, char *errbuf) 1403 | { 1404 | struct st_neverbleed_thread_data_t *thdata = get_thread_data(nb); 1405 | neverbleed_iobuf_t buf = {NULL}; 1406 | int ret = 1; 1407 | size_t index, type; 1408 | EVP_PKEY *pkey; 1409 | 1410 | iobuf_push_str(&buf, "load_key"); 1411 | iobuf_push_str(&buf, fn); 1412 | iobuf_transaction(&buf, thdata); 1413 | 1414 | if (iobuf_shift_num(&buf, &type) != 0 || iobuf_shift_num(&buf, &index) != 0) { 1415 | errno = 0; 1416 | dief("failed to parse response"); 1417 | } 1418 | 1419 | switch (type) { 1420 | case NEVERBLEED_TYPE_RSA: { 1421 | char *estr, *nstr; 1422 | 1423 | if ((estr = iobuf_shift_str(&buf)) == NULL || (nstr = iobuf_shift_str(&buf)) == NULL) { 1424 | errno = 0; 1425 | dief("failed to parse response"); 1426 | } 1427 | pkey = create_pkey(nb, index, estr, nstr); 1428 | break; 1429 | } 1430 | #ifdef NEVERBLEED_ECDSA 1431 | case NEVERBLEED_TYPE_ECDSA: { 1432 | size_t curve_name, pubkey_len; 1433 | void *pubkey_bytes; 1434 | 1435 | if (iobuf_shift_num(&buf, &curve_name) != 0 || (pubkey_bytes = iobuf_shift_bytes(&buf, &pubkey_len)) == NULL) { 1436 | errno = 0; 1437 | dief("failed to parse response"); 1438 | } 1439 | pkey = ecdsa_create_pkey(nb, index, (int)curve_name, pubkey_bytes, pubkey_len); 1440 | break; 1441 | } 1442 | #endif 1443 | default: { 1444 | char *errstr; 1445 | 1446 | if ((errstr = iobuf_shift_str(&buf)) == NULL) { 1447 | errno = 0; 1448 | dief("failed to parse response"); 1449 | } 1450 | 1451 | snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "%s", errstr); 1452 | return -1; 1453 | } 1454 | } 1455 | 1456 | iobuf_dispose(&buf); 1457 | 1458 | /* success */ 1459 | if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) { 1460 | snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "SSL_CTX_use_PrivateKey failed"); 1461 | ret = 0; 1462 | } 1463 | 1464 | EVP_PKEY_free(pkey); 1465 | return ret; 1466 | } 1467 | 1468 | static int load_key_stub(neverbleed_iobuf_t *buf) 1469 | { 1470 | char *fn; 1471 | FILE *fp = NULL; 1472 | RSA *rsa = NULL; 1473 | size_t key_index = SIZE_MAX; 1474 | char *estr = NULL, *nstr = NULL, errbuf[NEVERBLEED_ERRBUF_SIZE] = ""; 1475 | size_t type = NEVERBLEED_TYPE_ERROR; 1476 | EVP_PKEY *pkey = NULL; 1477 | #ifdef NEVERBLEED_ECDSA 1478 | const EC_GROUP *ec_group; 1479 | void *ec_pubkeybytes = NULL; 1480 | size_t ec_pubkeylen; 1481 | #endif 1482 | 1483 | if ((fn = iobuf_shift_str(buf)) == NULL) { 1484 | warnf("%s: failed to parse request", __FUNCTION__); 1485 | return -1; 1486 | } 1487 | 1488 | if ((fp = fopen(fn, "rt")) == NULL) { 1489 | strerror_r(errno, errbuf, sizeof(errbuf)); 1490 | goto Respond; 1491 | } 1492 | 1493 | if ((pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)) == NULL) { 1494 | snprintf(errbuf, sizeof(errbuf), "failed to parse the private key"); 1495 | goto Respond; 1496 | } 1497 | 1498 | switch (EVP_PKEY_base_id(pkey)) { 1499 | case EVP_PKEY_RSA: { 1500 | const BIGNUM *e, *n; 1501 | 1502 | rsa = EVP_PKEY_get1_RSA(pkey); 1503 | type = NEVERBLEED_TYPE_RSA; 1504 | RSA_get0_key(rsa, &n, &e, NULL); 1505 | estr = BN_bn2hex(e); 1506 | nstr = BN_bn2hex(n); 1507 | break; 1508 | } 1509 | case EVP_PKEY_EC: { 1510 | #ifdef NEVERBLEED_ECDSA 1511 | const EC_POINT *ec_pubkey; 1512 | EC_KEY *ec_key; 1513 | 1514 | ec_key = (EC_KEY *)EVP_PKEY_get0_EC_KEY(pkey); 1515 | type = NEVERBLEED_TYPE_ECDSA; 1516 | ec_group = EC_KEY_get0_group(ec_key); 1517 | ec_pubkey = EC_KEY_get0_public_key(ec_key); 1518 | ec_pubkeylen = EC_POINT_point2oct(ec_group, ec_pubkey, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); 1519 | if (!(ec_pubkeylen > 0 && (ec_pubkeybytes = malloc(ec_pubkeylen)) != NULL && 1520 | EC_POINT_point2oct(ec_group, ec_pubkey, POINT_CONVERSION_UNCOMPRESSED, ec_pubkeybytes, ec_pubkeylen, NULL) == 1521 | ec_pubkeylen)) 1522 | dief("failed to serialize EC public key"); 1523 | break; 1524 | #else 1525 | snprintf(errbuf, sizeof(errbuf), "ECDSA support requires OpenSSL >= 1.1.0, LibreSSL >= 2.9.1, or BoringSSL"); 1526 | goto Respond; 1527 | #endif 1528 | } 1529 | default: 1530 | snprintf(errbuf, sizeof(errbuf), "unsupported private key: %d", EVP_PKEY_base_id(pkey)); 1531 | goto Respond; 1532 | } 1533 | 1534 | /* store the key */ 1535 | key_index = daemon_set_pkey(pkey); 1536 | 1537 | Respond: 1538 | iobuf_dispose(buf); 1539 | iobuf_push_num(buf, type); 1540 | iobuf_push_num(buf, key_index); 1541 | switch (type) { 1542 | case NEVERBLEED_TYPE_RSA: 1543 | iobuf_push_str(buf, estr != NULL ? estr : ""); 1544 | iobuf_push_str(buf, nstr != NULL ? nstr : ""); 1545 | break; 1546 | #ifdef NEVERBLEED_ECDSA 1547 | case NEVERBLEED_TYPE_ECDSA: 1548 | iobuf_push_num(buf, EC_GROUP_get_curve_name(ec_group)); 1549 | iobuf_push_bytes(buf, ec_pubkeybytes, ec_pubkeylen); 1550 | break; 1551 | #endif 1552 | default: 1553 | iobuf_push_str(buf, errbuf); 1554 | } 1555 | if (rsa != NULL) 1556 | RSA_free(rsa); 1557 | if (pkey != NULL) 1558 | EVP_PKEY_free(pkey); 1559 | if (estr != NULL) 1560 | OPENSSL_free(estr); 1561 | if (nstr != NULL) 1562 | OPENSSL_free(nstr); 1563 | #ifdef NEVERBLEED_ECDSA 1564 | if (ec_pubkeybytes != NULL) 1565 | free(ec_pubkeybytes); 1566 | #endif 1567 | if (fp != NULL) 1568 | fclose(fp); 1569 | 1570 | return 0; 1571 | } 1572 | 1573 | int neverbleed_setuidgid(neverbleed_t *nb, const char *user, int change_socket_ownership) 1574 | { 1575 | struct st_neverbleed_thread_data_t *thdata = get_thread_data(nb); 1576 | neverbleed_iobuf_t buf = {NULL}; 1577 | size_t ret; 1578 | 1579 | iobuf_push_str(&buf, "setuidgid"); 1580 | iobuf_push_str(&buf, user); 1581 | iobuf_push_num(&buf, change_socket_ownership); 1582 | iobuf_transaction(&buf, thdata); 1583 | 1584 | if (iobuf_shift_num(&buf, &ret) != 0) { 1585 | errno = 0; 1586 | dief("failed to parse response"); 1587 | } 1588 | iobuf_dispose(&buf); 1589 | 1590 | return (int)ret; 1591 | } 1592 | 1593 | static int setuidgid_stub(neverbleed_iobuf_t *buf) 1594 | { 1595 | const char *user; 1596 | size_t change_socket_ownership; 1597 | struct passwd pwbuf, *pw; 1598 | char pwstrbuf[65536]; /* should be large enough */ 1599 | int ret = -1; 1600 | 1601 | if ((user = iobuf_shift_str(buf)) == NULL || iobuf_shift_num(buf, &change_socket_ownership) != 0) { 1602 | errno = 0; 1603 | warnf("%s: failed to parse request", __FUNCTION__); 1604 | return -1; 1605 | } 1606 | 1607 | errno = 0; 1608 | if (getpwnam_r(user, &pwbuf, pwstrbuf, sizeof(pwstrbuf), &pw) != 0) { 1609 | warnf("%s: getpwnam_r failed", __FUNCTION__); 1610 | goto Respond; 1611 | } 1612 | if (pw == NULL) { 1613 | warnf("%s: failed to obtain information of user:%s", __FUNCTION__, user); 1614 | goto Respond; 1615 | } 1616 | 1617 | if (change_socket_ownership) { 1618 | char *dir; 1619 | if (chown(daemon_vars.nb->sun_.sun_path, pw->pw_uid, pw->pw_gid) != 0) 1620 | dief("chown failed for:%s", daemon_vars.nb->sun_.sun_path); 1621 | dir = dirname(daemon_vars.nb->sun_.sun_path); 1622 | if (chown(dir, pw->pw_uid, pw->pw_gid) != 0) 1623 | dief("chown failed for:%s", dir); 1624 | free(dir); 1625 | } 1626 | 1627 | /* setuidgid */ 1628 | if (setgid(pw->pw_gid) != 0) { 1629 | warnf("%s: setgid(%d) failed", __FUNCTION__, (int)pw->pw_gid); 1630 | goto Respond; 1631 | } 1632 | if (initgroups(pw->pw_name, pw->pw_gid) != 0) { 1633 | warnf("%s: initgroups(%s, %d) failed", __FUNCTION__, pw->pw_name, (int)pw->pw_gid); 1634 | goto Respond; 1635 | } 1636 | if (setuid(pw->pw_uid) != 0) { 1637 | warnf("%s: setuid(%d) failed\n", __FUNCTION__, (int)pw->pw_uid); 1638 | goto Respond; 1639 | } 1640 | ret = 0; 1641 | 1642 | Respond: 1643 | iobuf_dispose(buf); 1644 | iobuf_push_num(buf, ret); 1645 | return 0; 1646 | } 1647 | 1648 | #if NEVERBLEED_HAS_PTHREAD_SETAFFINITY_NP 1649 | int neverbleed_setaffinity(neverbleed_t *nb, NEVERBLEED_CPU_SET_T *cpuset) 1650 | { 1651 | struct st_neverbleed_thread_data_t *thdata = get_thread_data(nb); 1652 | neverbleed_iobuf_t buf = {NULL}; 1653 | size_t ret; 1654 | 1655 | iobuf_push_str(&buf, "setaffinity"); 1656 | iobuf_push_bytes(&buf, cpuset, sizeof(*cpuset)); 1657 | iobuf_transaction(&buf, thdata); 1658 | 1659 | if (iobuf_shift_num(&buf, &ret) != 0) { 1660 | errno = 0; 1661 | dief("failed to parse response"); 1662 | } 1663 | iobuf_dispose(&buf); 1664 | 1665 | return (int)ret; 1666 | } 1667 | 1668 | static int setaffinity_stub(neverbleed_iobuf_t *buf) 1669 | { 1670 | char *cpuset_bytes; 1671 | size_t cpuset_len; 1672 | NEVERBLEED_CPU_SET_T cpuset; 1673 | int ret = 1; 1674 | 1675 | if ((cpuset_bytes = iobuf_shift_bytes(buf, &cpuset_len)) == NULL) { 1676 | errno = 0; 1677 | warnf("%s: failed to parse request", __FUNCTION__); 1678 | return -1; 1679 | } 1680 | 1681 | assert(cpuset_len == sizeof(NEVERBLEED_CPU_SET_T)); 1682 | memcpy(&cpuset, cpuset_bytes, cpuset_len); 1683 | 1684 | #ifdef __NetBSD__ 1685 | ret = pthread_setaffinity_np(pthread_self(), cpuset_size(cpuset), cpuset); 1686 | #else 1687 | ret = pthread_setaffinity_np(pthread_self(), sizeof(NEVERBLEED_CPU_SET_T), &cpuset); 1688 | #endif 1689 | if (ret != 0) { 1690 | ret = 1; 1691 | goto Respond; 1692 | } 1693 | 1694 | ret = 0; 1695 | 1696 | Respond: 1697 | iobuf_dispose(buf); 1698 | iobuf_push_num(buf, ret); 1699 | return 0; 1700 | } 1701 | #endif 1702 | 1703 | __attribute__((noreturn)) static void *daemon_close_notify_thread(void *_close_notify_fd) 1704 | { 1705 | int close_notify_fd = (int)((char *)_close_notify_fd - (char *)NULL); 1706 | char b; 1707 | ssize_t r; 1708 | 1709 | Redo: 1710 | r = read(close_notify_fd, &b, 1); 1711 | if (r == -1 && errno == EINTR) 1712 | goto Redo; 1713 | if (r > 0) 1714 | goto Redo; 1715 | /* close or error */ 1716 | 1717 | /* unlink the temporary directory and socket file */ 1718 | unlink_dir(dirname(daemon_vars.nb->sun_.sun_path)); 1719 | 1720 | _exit(0); 1721 | } 1722 | 1723 | static int del_pkey_stub(neverbleed_iobuf_t *buf) 1724 | { 1725 | size_t key_index; 1726 | 1727 | if (iobuf_shift_num(buf, &key_index) != 0) { 1728 | errno = 0; 1729 | warnf("%s: failed to parse request", __FUNCTION__); 1730 | return -1; 1731 | } 1732 | 1733 | pthread_mutex_lock(&daemon_vars.keys.lock); 1734 | /* set slot as available */ 1735 | if (key_index < daemon_vars.keys.num_slots) { 1736 | EVP_PKEY_free(daemon_vars.keys.slots[key_index].pkey); 1737 | daemon_vars.keys.slots[key_index].next_empty = daemon_vars.keys.first_empty; 1738 | daemon_vars.keys.first_empty = key_index; 1739 | } else { 1740 | warnf("%s: invalid key index %zu", __FUNCTION__, key_index); 1741 | } 1742 | pthread_mutex_unlock(&daemon_vars.keys.lock); 1743 | 1744 | return 0; 1745 | } 1746 | 1747 | #define offload_start(stub, buf) ((stub)(buf)) 1748 | 1749 | #if USE_OFFLOAD 1750 | #ifdef OPENSSL_IS_BORINGSSL 1751 | 1752 | static int offload_resume(struct engine_request *req) 1753 | { 1754 | size_t outlen; 1755 | 1756 | if (do_epoll_ctl(conn_ctx.epollfd, EPOLL_CTL_DEL, req->async_fd, NULL) != 0) 1757 | dief("epoll_ctl failed:%d\n", errno); 1758 | 1759 | /* get result */ 1760 | if (bssl_qat_async_ctx_copy_result(req->async_ctx, req->data.output, &outlen, sizeof(req->data.output)) != 0) 1761 | dief("failed to obtain offload result\n"); 1762 | if (outlen > sizeof(req->data.output)) 1763 | dief("RSA output is unexpectedly large\n"); 1764 | /* save the result */ 1765 | iobuf_dispose(req->buf); 1766 | iobuf_push_bytes(req->buf, req->data.output, outlen); 1767 | 1768 | req->buf->processing = 0; 1769 | offload_free_request(req); 1770 | 1771 | return 0; 1772 | } 1773 | 1774 | #else 1775 | 1776 | static int offload_jobfunc(void *_req) 1777 | { 1778 | struct engine_request *req = *(void **)_req; 1779 | return req->stub(req->buf); 1780 | } 1781 | 1782 | #undef offload_start 1783 | static int offload_start(int (*stub)(neverbleed_iobuf_t *), neverbleed_iobuf_t *buf) 1784 | { 1785 | /* if engine is not used, run the stub synchronously */ 1786 | if (!use_offload) 1787 | return stub(buf); 1788 | 1789 | buf->processing = 1; 1790 | 1791 | struct engine_request *req = malloc(sizeof(*req)); 1792 | if (req == NULL) 1793 | dief("no memory"); 1794 | *req = (struct engine_request){.buf = buf, .async_fd = -1, .stub = stub}; 1795 | 1796 | if ((req->async.ctx = ASYNC_WAIT_CTX_new()) == NULL) 1797 | dief("failed to create ASYNC_WAIT_CTX\n"); 1798 | 1799 | int ret; 1800 | switch (ASYNC_start_job(&req->async.job, req->async.ctx, &ret, offload_jobfunc, &req, sizeof(req))) { 1801 | case ASYNC_PAUSE: /* operation running async; register fd and bail out */ 1802 | register_wait_fd(req); 1803 | return 0; 1804 | case ASYNC_FINISH: /* completed synchronously */ 1805 | buf->processing = 0; 1806 | break; 1807 | default: 1808 | dief("ASYNC_start_job errored\n"); 1809 | break; 1810 | } 1811 | 1812 | offload_free_request(req); 1813 | 1814 | return ret; 1815 | } 1816 | 1817 | static int offload_resume(struct engine_request *req) 1818 | { 1819 | int ret; 1820 | 1821 | switch (ASYNC_start_job(&req->async.job, req->async.ctx, &ret, offload_jobfunc, &req, sizeof(req))) { 1822 | case ASYNC_PAUSE: 1823 | /* assume that wait fd is unchanged */ 1824 | return 0; 1825 | case ASYNC_FINISH: 1826 | if (do_epoll_ctl(conn_ctx.epollfd, EPOLL_CTL_DEL, req->async_fd, NULL) != 0) 1827 | dief("epoll_ctl failed:%d\n", errno); 1828 | break; 1829 | default: 1830 | dief("ASYNC_start_job failed\n"); 1831 | break; 1832 | } 1833 | 1834 | /* job done */ 1835 | req->buf->processing = 0; 1836 | offload_free_request(req); 1837 | 1838 | return ret; 1839 | } 1840 | 1841 | #endif 1842 | #endif 1843 | 1844 | /** 1845 | * This function waits for the provided socket to become readable, then calls `nanosleep(1)` before returning. 1846 | * The intention behind sleep is to provide the application to complete its event loop before the neverbleed process starts 1847 | * spending CPU cycles on the time-consuming RSA operation. 1848 | * In addition, when QAT is used, this function processes completion notifications from QAT and sends the responses. 1849 | */ 1850 | static int wait_for_data(int cleanup) 1851 | { 1852 | #if USE_OFFLOAD 1853 | 1854 | struct epoll_event events[20]; 1855 | int has_read = 0, num_events; 1856 | 1857 | do { 1858 | while ((num_events = epoll_wait(conn_ctx.epollfd, events, sizeof(events) / sizeof(events[0]), -1)) == -1 && 1859 | (errno == EAGAIN || errno == EINTR)) 1860 | ; 1861 | if (num_events == -1) 1862 | dief("epoll_wait(2):%d\n", errno); 1863 | for (int i = 0; i < num_events; ++i) { 1864 | if (events[i].data.ptr == NULL) { 1865 | has_read = 1; 1866 | } else { 1867 | struct engine_request *req = events[i].data.ptr; 1868 | int ret; 1869 | if ((ret = offload_resume(req)) != 0) 1870 | return ret; 1871 | if ((ret = send_responses(0)) != 0) 1872 | return ret; 1873 | } 1874 | } 1875 | } while (!has_read); 1876 | 1877 | #else 1878 | 1879 | fd_set rfds; 1880 | int ret; 1881 | FD_ZERO(&rfds); 1882 | if (!cleanup) 1883 | FD_SET(conn_ctx.sockfd, &rfds); 1884 | 1885 | while ((ret = select(conn_ctx.sockfd + 1, &rfds, NULL, NULL, NULL)) == -1 && (errno == EAGAIN || errno == EINTR)) 1886 | ; 1887 | if (ret == -1) 1888 | dief("select(2):%d\n", errno); 1889 | 1890 | #endif 1891 | 1892 | // yield when data is available 1893 | struct timespec tv = {.tv_nsec = 1}; 1894 | (void)nanosleep(&tv, NULL); 1895 | 1896 | return 0; 1897 | } 1898 | 1899 | static void *daemon_conn_thread(void *_sock_fd) 1900 | { 1901 | conn_ctx.sockfd = (int)((char *)_sock_fd - (char *)NULL); 1902 | conn_ctx.responses.next = &conn_ctx.responses.first; 1903 | neverbleed_iobuf_t *buf = NULL; 1904 | 1905 | #if USE_OFFLOAD 1906 | if ((conn_ctx.epollfd = epoll_create1(EPOLL_CLOEXEC)) == -1) 1907 | dief("epoll_create1 failed:%d\n", errno); 1908 | { 1909 | struct epoll_event ev = {.events = EPOLLIN}; 1910 | if (do_epoll_ctl(conn_ctx.epollfd, EPOLL_CTL_ADD, conn_ctx.sockfd, &ev) != 0) 1911 | dief("epoll_ctl failed:%d\n", errno); 1912 | } 1913 | #endif 1914 | 1915 | { /* authenticate */ 1916 | unsigned char auth_token[NEVERBLEED_AUTH_TOKEN_SIZE]; 1917 | if (read_nbytes(conn_ctx.sockfd, &auth_token, sizeof(auth_token)) != 0) { 1918 | warnf("failed to receive authencication token from client"); 1919 | goto Exit; 1920 | } 1921 | if (memcmp(auth_token, daemon_vars.nb->auth_token, NEVERBLEED_AUTH_TOKEN_SIZE) != 0) { 1922 | warnf("client authentication failed"); 1923 | goto Exit; 1924 | } 1925 | } 1926 | 1927 | while (1) { 1928 | if (wait_for_data(0) != 0) 1929 | break; 1930 | free(buf); 1931 | buf = malloc(sizeof(*buf)); 1932 | if (buf == NULL) 1933 | dief("no memory"); 1934 | *buf = (neverbleed_iobuf_t){}; 1935 | char *cmd; 1936 | if (iobuf_read(buf, conn_ctx.sockfd) != 0) { 1937 | if (errno != 0) 1938 | warnf("read error"); 1939 | break; 1940 | } 1941 | if ((cmd = iobuf_shift_str(buf)) == NULL) { 1942 | errno = 0; 1943 | warnf("failed to parse request"); 1944 | break; 1945 | } 1946 | #if !defined(OPENSSL_IS_BORINGSSL) 1947 | if (strcmp(cmd, "priv_enc") == 0) { 1948 | if (offload_start(priv_enc_stub, buf) != 0) 1949 | break; 1950 | } else if (strcmp(cmd, "priv_dec") == 0) { 1951 | if (offload_start(priv_dec_stub, buf) != 0) 1952 | break; 1953 | } else if (strcmp(cmd, "sign") == 0) { 1954 | if (offload_start(sign_stub, buf) != 0) 1955 | break; 1956 | #ifdef NEVERBLEED_ECDSA 1957 | } else if (strcmp(cmd, "ecdsa_sign") == 0) { 1958 | if (ecdsa_sign_stub(buf) != 0) 1959 | break; 1960 | #endif 1961 | } else 1962 | #endif 1963 | if (strcmp(cmd, "digestsign") == 0) { 1964 | if (digestsign_stub(buf) != 0) 1965 | break; 1966 | } else if (strcmp(cmd, "digestsign-rsa") == 0) { 1967 | if (offload_start(digestsign_stub, buf) != 0) 1968 | break; 1969 | } else if (strcmp(cmd, "decrypt") == 0) { 1970 | if (offload_start(decrypt_stub, buf) != 0) 1971 | break; 1972 | } else if (strcmp(cmd, "load_key") == 0) { 1973 | if (load_key_stub(buf) != 0) 1974 | break; 1975 | } else if (strcmp(cmd, "del_pkey") == 0) { 1976 | if (del_pkey_stub(buf) != 0) 1977 | break; 1978 | iobuf_dispose(buf); 1979 | // "del_pkey" command is fire-and-forget, it cannot fail, so doesn't have a response 1980 | continue; 1981 | } else if (strcmp(cmd, "setuidgid") == 0) { 1982 | if (setuidgid_stub(buf) != 0) 1983 | break; 1984 | #if NEVERBLEED_HAS_PTHREAD_SETAFFINITY_NP 1985 | } else if (strcmp(cmd, "setaffinity") == 0) { 1986 | if (setaffinity_stub(buf) != 0) 1987 | break; 1988 | #endif 1989 | } else { 1990 | warnf("unknown command:%s", cmd); 1991 | break; 1992 | } 1993 | /* add response to chain */ 1994 | *conn_ctx.responses.next = buf; 1995 | conn_ctx.responses.next = &buf->next; 1996 | buf = NULL; /* do not free */ 1997 | 1998 | /* send responses if possible */ 1999 | if (send_responses(0) != 0) 2000 | break; 2001 | } 2002 | 2003 | Exit: 2004 | free(buf); 2005 | /* run the loop while async ops are running */ 2006 | while (conn_ctx.responses.first != NULL) 2007 | wait_for_data(1); 2008 | 2009 | close(conn_ctx.sockfd); 2010 | #ifdef __linux 2011 | close(conn_ctx.epollfd); 2012 | #endif 2013 | 2014 | return NULL; 2015 | } 2016 | 2017 | #if !(defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) 2018 | #define closefrom my_closefrom 2019 | static void my_closefrom(int lowfd) 2020 | { 2021 | /* On linux, try close_range (2), then fall back to the slow loop if it fails. */ 2022 | #if defined(__linux__) && defined(__NR_close_range) 2023 | if (syscall(__NR_close_range, lowfd, ~0, 0) == 0) 2024 | return; 2025 | #endif 2026 | 2027 | for (int fd = (int)sysconf(_SC_OPEN_MAX) - 1; fd >= lowfd; --fd) 2028 | (void)close(fd); 2029 | } 2030 | #endif 2031 | 2032 | static void cleanup_fds(int listen_fd, int close_notify_fd) 2033 | { 2034 | int maxfd, k; 2035 | 2036 | maxfd = 0; 2037 | if (listen_fd > maxfd) { 2038 | maxfd = listen_fd; 2039 | } 2040 | if (close_notify_fd > maxfd) { 2041 | maxfd = close_notify_fd; 2042 | } 2043 | for (k = 0; k < maxfd; k++) { 2044 | if (k == listen_fd || k == close_notify_fd) 2045 | continue; 2046 | switch (k) { 2047 | case STDOUT_FILENO: 2048 | case STDERR_FILENO: 2049 | case STDIN_FILENO: 2050 | break; 2051 | default: 2052 | (void)close(k); 2053 | } 2054 | } 2055 | closefrom(maxfd + 1); 2056 | } 2057 | 2058 | __attribute__((noreturn)) static void daemon_main(int listen_fd, int close_notify_fd, const char *tempdir) 2059 | { 2060 | pthread_t tid; 2061 | pthread_attr_t thattr; 2062 | int sock_fd; 2063 | 2064 | cleanup_fds(listen_fd, close_notify_fd); 2065 | pthread_attr_init(&thattr); 2066 | pthread_attr_setdetachstate(&thattr, 1); 2067 | 2068 | switch (neverbleed_offload) { 2069 | case NEVERBLEED_OFFLOAD_QAT_ON: 2070 | case NEVERBLEED_OFFLOAD_QAT_AUTO: { 2071 | #if USE_OFFLOAD && defined(OPENSSL_IS_BORINGSSL) 2072 | ENGINE_load_qat(); 2073 | bssl_qat_set_default_string("RSA"); 2074 | use_offload = ENGINE_QAT_PTR_GET() != NULL; 2075 | #elif USE_OFFLOAD && !defined(OPENSSL_IS_BORINGSSL) 2076 | ENGINE *qat = ENGINE_by_id("qatengine"); 2077 | if (qat != NULL && ENGINE_init(qat)) { 2078 | if (!ENGINE_set_default_RSA(qat)) 2079 | dief("failed to assign RSA operations to QAT\n"); 2080 | use_offload = 1; 2081 | } 2082 | #endif 2083 | if (!use_offload && neverbleed_offload == NEVERBLEED_OFFLOAD_QAT_ON) 2084 | dief("use of QAT is forced but unavailable\n"); 2085 | } break; 2086 | default: 2087 | break; 2088 | } 2089 | 2090 | if (pthread_create(&tid, &thattr, daemon_close_notify_thread, (char *)NULL + close_notify_fd) != 0) 2091 | dief("pthread_create failed"); 2092 | 2093 | while (1) { 2094 | while ((sock_fd = accept(listen_fd, NULL, NULL)) == -1) 2095 | ; 2096 | if (pthread_create(&tid, &thattr, daemon_conn_thread, (char *)NULL + sock_fd) != 0) 2097 | dief("pthread_create failed"); 2098 | } 2099 | } 2100 | 2101 | static void set_signal_handler(int signo, void (*cb)(int signo)) 2102 | { 2103 | struct sigaction action; 2104 | 2105 | memset(&action, 0, sizeof(action)); 2106 | sigemptyset(&action.sa_mask); 2107 | action.sa_handler = cb; 2108 | sigaction(signo, &action, NULL); 2109 | } 2110 | 2111 | #ifndef NEVERBLEED_OPAQUE_RSA_METHOD 2112 | 2113 | static RSA_METHOD static_rsa_method = { 2114 | "privsep RSA method", /* name */ 2115 | NULL, /* rsa_pub_enc */ 2116 | NULL, /* rsa_pub_dec */ 2117 | priv_enc_proxy, /* rsa_priv_enc */ 2118 | priv_dec_proxy, /* rsa_priv_dec */ 2119 | NULL, /* rsa_mod_exp */ 2120 | NULL, /* bn_mod_exp */ 2121 | NULL, /* init */ 2122 | NULL, /* finish */ 2123 | RSA_FLAG_SIGN_VER, /* flags */ 2124 | NULL, /* app data */ 2125 | sign_proxy, /* rsa_sign */ 2126 | NULL, /* rsa_verify */ 2127 | NULL /* rsa_keygen */ 2128 | }; 2129 | 2130 | #endif 2131 | 2132 | int neverbleed_init(neverbleed_t *nb, char *errbuf) 2133 | { 2134 | int pipe_fds[2] = {-1, -1}, listen_fd = -1; 2135 | char *tempdir = NULL; 2136 | 2137 | /* setup the daemon */ 2138 | if (pipe(pipe_fds) != 0) { 2139 | snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "pipe(2) failed:%s", strerror(errno)); 2140 | goto Fail; 2141 | } 2142 | set_cloexec(pipe_fds[1]); 2143 | if ((tempdir = strdup("/tmp/openssl-privsep.XXXXXX")) == NULL) { 2144 | snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "no memory"); 2145 | goto Fail; 2146 | } 2147 | if (mkdtemp(tempdir) == NULL) { 2148 | snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "failed to create temporary directory under /tmp:%s", strerror(errno)); 2149 | goto Fail; 2150 | } 2151 | memset(&nb->sun_, 0, sizeof(nb->sun_)); 2152 | nb->sun_.sun_family = AF_UNIX; 2153 | snprintf(nb->sun_.sun_path, sizeof(nb->sun_.sun_path), "%s/_", tempdir); 2154 | RAND_bytes(nb->auth_token, sizeof(nb->auth_token)); 2155 | if ((listen_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { 2156 | snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "socket(2) failed:%s", strerror(errno)); 2157 | goto Fail; 2158 | } 2159 | if (bind(listen_fd, (void *)&nb->sun_, sizeof(nb->sun_)) != 0) { 2160 | snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "failed to bind to %s:%s", nb->sun_.sun_path, strerror(errno)); 2161 | goto Fail; 2162 | } 2163 | if (listen(listen_fd, SOMAXCONN) != 0) { 2164 | snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "listen(2) failed:%s", strerror(errno)); 2165 | goto Fail; 2166 | } 2167 | nb->daemon_pid = fork(); 2168 | switch (nb->daemon_pid) { 2169 | case -1: 2170 | snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "fork(2) failed:%s", strerror(errno)); 2171 | goto Fail; 2172 | case 0: 2173 | close(pipe_fds[1]); 2174 | #if defined(__linux__) 2175 | prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); 2176 | prctl(PR_SET_PDEATHSIG, SIGTERM); 2177 | #elif defined(__FreeBSD__) 2178 | int dumpable = PROC_TRACE_CTL_DISABLE; 2179 | procctl(P_PID, 0, PROC_TRACE_CTL, &dumpable); 2180 | #elif defined(__sun) 2181 | setpflags(__PROC_PROTECT, 1); 2182 | #elif defined(__APPLE__) 2183 | ptrace(PT_DENY_ATTACH, 0, 0, 0); 2184 | #endif 2185 | set_signal_handler(SIGTERM, SIG_IGN); 2186 | if (neverbleed_post_fork_cb != NULL) 2187 | neverbleed_post_fork_cb(); 2188 | daemon_vars.nb = nb; 2189 | daemon_main(listen_fd, pipe_fds[0], tempdir); 2190 | break; 2191 | default: 2192 | break; 2193 | } 2194 | close(listen_fd); 2195 | listen_fd = -1; 2196 | close(pipe_fds[0]); 2197 | pipe_fds[0] = -1; 2198 | 2199 | #if defined(OPENSSL_IS_BORINGSSL) 2200 | nb->engine = NULL; 2201 | #else 2202 | { /* setup engine */ 2203 | const RSA_METHOD *rsa_default_method; 2204 | RSA_METHOD *rsa_method; 2205 | #ifdef NEVERBLEED_ECDSA 2206 | const EC_KEY_METHOD *ecdsa_default_method; 2207 | EC_KEY_METHOD *ecdsa_method; 2208 | #endif 2209 | 2210 | #ifdef NEVERBLEED_OPAQUE_RSA_METHOD 2211 | rsa_default_method = RSA_PKCS1_OpenSSL(); 2212 | rsa_method = RSA_meth_dup(rsa_default_method); 2213 | 2214 | RSA_meth_set1_name(rsa_method, "privsep RSA method"); 2215 | RSA_meth_set_priv_enc(rsa_method, priv_enc_proxy); 2216 | RSA_meth_set_priv_dec(rsa_method, priv_dec_proxy); 2217 | RSA_meth_set_sign(rsa_method, sign_proxy); 2218 | #else 2219 | rsa_default_method = RSA_PKCS1_SSLeay(); 2220 | rsa_method = &static_rsa_method; 2221 | 2222 | rsa_method->rsa_pub_enc = rsa_default_method->rsa_pub_enc; 2223 | rsa_method->rsa_pub_dec = rsa_default_method->rsa_pub_dec; 2224 | rsa_method->rsa_verify = rsa_default_method->rsa_verify; 2225 | rsa_method->bn_mod_exp = rsa_default_method->bn_mod_exp; 2226 | #endif 2227 | 2228 | #ifdef NEVERBLEED_ECDSA 2229 | ecdsa_default_method = EC_KEY_get_default_method(); 2230 | ecdsa_method = EC_KEY_METHOD_new(ecdsa_default_method); 2231 | 2232 | /* it seems sign_sig and sign_setup is not used in TLS ECDSA. */ 2233 | EC_KEY_METHOD_set_sign(ecdsa_method, ecdsa_sign_proxy, NULL, NULL); 2234 | #endif 2235 | 2236 | if ((nb->engine = ENGINE_new()) == NULL || !ENGINE_set_id(nb->engine, "neverbleed") || 2237 | !ENGINE_set_name(nb->engine, "privilege separation software engine") || !ENGINE_set_RSA(nb->engine, rsa_method) 2238 | #ifdef NEVERBLEED_ECDSA 2239 | || !ENGINE_set_EC(nb->engine, ecdsa_method) 2240 | #endif 2241 | ) { 2242 | snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "failed to initialize the OpenSSL engine"); 2243 | goto Fail; 2244 | } 2245 | ENGINE_add(nb->engine); 2246 | } 2247 | #endif 2248 | 2249 | /* setup thread key */ 2250 | pthread_key_create(&nb->thread_key, dispose_thread_data); 2251 | 2252 | free(tempdir); 2253 | return 0; 2254 | Fail: 2255 | if (pipe_fds[0] != -1) 2256 | close(pipe_fds[0]); 2257 | if (pipe_fds[1] != -1) 2258 | close(pipe_fds[1]); 2259 | if (tempdir != NULL) { 2260 | unlink_dir(tempdir); 2261 | free(tempdir); 2262 | } 2263 | if (listen_fd != -1) 2264 | close(listen_fd); 2265 | if (nb->engine != NULL) { 2266 | ENGINE_free(nb->engine); 2267 | nb->engine = NULL; 2268 | } 2269 | return -1; 2270 | } 2271 | 2272 | void (*neverbleed_post_fork_cb)(void) = NULL; 2273 | void (*neverbleed_transaction_cb)(neverbleed_iobuf_t *, int) = NULL; 2274 | enum neverbleed_offload_type neverbleed_offload = NEVERBLEED_OFFLOAD_OFF; 2275 | -------------------------------------------------------------------------------- /neverbleed.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Kazuho Oku, DeNA Co., Ltd. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | #ifndef NEVERBLEED_H 23 | #define NEVERBLEED_H 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #ifdef __FreeBSD__ 30 | #include 31 | #endif 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | #if (defined(__linux__) && !defined(__ANDROID__)) || defined(__FreeBSD__) || defined(__NetBSD__) 37 | #define NEVERBLEED_HAS_PTHREAD_SETAFFINITY_NP 1 38 | #if defined(__linux__) 39 | #define NEVERBLEED_CPU_SET_T cpu_set_t 40 | #else 41 | #define NEVERBLEED_CPU_SET_T cpuset_t 42 | #endif 43 | #endif 44 | 45 | #define NEVERBLEED_ERRBUF_SIZE (256) 46 | #define NEVERBLEED_AUTH_TOKEN_SIZE 32 47 | 48 | typedef struct st_neverbleed_t { 49 | ENGINE *engine; 50 | pid_t daemon_pid; 51 | struct sockaddr_un sun_; 52 | pthread_key_t thread_key; 53 | unsigned char auth_token[NEVERBLEED_AUTH_TOKEN_SIZE]; 54 | } neverbleed_t; 55 | 56 | typedef struct st_neverbleed_iobuf_t { 57 | char *buf; 58 | char *start; 59 | char *end; 60 | size_t capacity; 61 | struct st_neverbleed_iobuf_t *next; 62 | unsigned processing : 1; 63 | } neverbleed_iobuf_t; 64 | 65 | /** 66 | * initializes the privilege separation engine (returns 0 if successful) 67 | */ 68 | int neverbleed_init(neverbleed_t *nb, char *errbuf); 69 | /** 70 | * loads a private key file (returns 1 if successful) 71 | */ 72 | int neverbleed_load_private_key_file(neverbleed_t *nb, SSL_CTX *ctx, const char *fn, char *errbuf); 73 | /** 74 | * setuidgid (also changes the file permissions so that `user` can connect to the daemon, if change_socket_ownership is non-zero) 75 | */ 76 | int neverbleed_setuidgid(neverbleed_t *nb, const char *user, int change_socket_ownership); 77 | 78 | /** 79 | * builds a digestsign request 80 | */ 81 | void neverbleed_start_digestsign(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const EVP_MD *md, const void *input, size_t len, 82 | int rsa_pss); 83 | /** 84 | * parses a digestsign response 85 | */ 86 | void neverbleed_finish_digestsign(neverbleed_iobuf_t *buf, void **digest, size_t *digest_len); 87 | /** 88 | * builds a RSA decrypt request 89 | */ 90 | void neverbleed_start_decrypt(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const void *input, size_t len); 91 | /** 92 | * parses a decrypt response 93 | */ 94 | void neverbleed_finish_decrypt(neverbleed_iobuf_t *buf, void **digest, size_t *digest_len); 95 | 96 | #if NEVERBLEED_HAS_PTHREAD_SETAFFINITY_NP 97 | /** 98 | * set the cpu affinity for the neverbleed thread (returns 0 if successful) 99 | */ 100 | int neverbleed_setaffinity(neverbleed_t *nb, NEVERBLEED_CPU_SET_T *cpuset); 101 | #endif 102 | 103 | /** 104 | * an optional callback that can be registered by the application for doing stuff immediately after the neverbleed process is being 105 | * spawned 106 | */ 107 | extern void (*neverbleed_post_fork_cb)(void); 108 | /** 109 | * An optional callback used for replacing `iobuf_transaction`; i.e., the logic that sends the request and receives the response. 110 | * 111 | * If `responseless` equals `1`, the ownership of stack-allocated `req` is given to the callback. In this case, `req` must be free'd using `neverbleed_iobuf_dispose` 112 | */ 113 | extern void (*neverbleed_transaction_cb)(neverbleed_iobuf_t *req, int responseless); 114 | 115 | typedef void (*neverbleed_cb)(int); 116 | 117 | int neverbleed_get_fd(neverbleed_t *nb); 118 | static size_t neverbleed_iobuf_size(neverbleed_iobuf_t *buf); 119 | void neverbleed_iobuf_dispose(neverbleed_iobuf_t *buf); 120 | void neverbleed_transaction_read(neverbleed_t *nb, neverbleed_iobuf_t *buf); 121 | void neverbleed_transaction_write(neverbleed_t *nb, neverbleed_iobuf_t *buf); 122 | 123 | /** 124 | * if set to a non-zero value, RSA operations are offloaded 125 | */ 126 | extern enum neverbleed_offload_type { 127 | NEVERBLEED_OFFLOAD_OFF = 0, 128 | NEVERBLEED_OFFLOAD_QAT_ON, 129 | NEVERBLEED_OFFLOAD_QAT_AUTO, 130 | } neverbleed_offload; 131 | 132 | /* inline function definitions */ 133 | 134 | inline size_t neverbleed_iobuf_size(neverbleed_iobuf_t *buf) 135 | { 136 | return buf->end - buf->start; 137 | } 138 | 139 | #ifdef __cplusplus 140 | } 141 | #endif 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Kazuho Oku, DeNA Co., Ltd. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | #if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_EC) && \ 33 | (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2090100fL) 34 | #define NEVERBLEED_TEST_ECDSA 35 | #endif 36 | 37 | #ifdef NEVERBLEED_TEST_ECDSA 38 | #include 39 | #endif 40 | #include 41 | #include 42 | 43 | #include "neverbleed.h" 44 | 45 | #ifdef NEVERBLEED_TEST_ECDSA 46 | static void setup_ecc_key(SSL_CTX *ssl_ctx) 47 | { 48 | int nid = NID_X9_62_prime256v1; 49 | EC_KEY *key = EC_KEY_new_by_curve_name(nid); 50 | if (key == NULL) { 51 | fprintf(stderr, "Failed to create curve \"%s\"\n", OBJ_nid2sn(nid)); 52 | return; 53 | } 54 | SSL_CTX_set_tmp_ecdh(ssl_ctx, key); 55 | EC_KEY_free(key); 56 | } 57 | #endif 58 | 59 | int dumb_https_server(unsigned short port, SSL_CTX *ctx) 60 | { 61 | int listen_fd, reuse_flag; 62 | struct sockaddr_in sin = {}; 63 | 64 | if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 65 | fprintf(stderr, "failed to create socket:%s\n", strerror(errno)); 66 | return 111; 67 | } 68 | reuse_flag = 1; 69 | setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag, sizeof(reuse_flag)); 70 | sin.sin_family = AF_INET; 71 | sin.sin_addr.s_addr = htonl(0x7f000001); 72 | sin.sin_port = htons(8888); 73 | if (bind(listen_fd, (void *)&sin, sizeof(sin)) != 0) { 74 | fprintf(stderr, "bind failed:%s\n", strerror(errno)); 75 | return 111; 76 | } 77 | if (listen(listen_fd, SOMAXCONN) != 0) { 78 | fprintf(stderr, "listen failed:%s\n", strerror(errno)); 79 | return 111; 80 | } 81 | 82 | while (1) { 83 | int conn_fd; 84 | SSL *ssl; 85 | char buf[4096]; 86 | /* accept connection */ 87 | while ((conn_fd = accept(listen_fd, NULL, NULL)) == -1 && errno == EINTR) 88 | ; 89 | if (conn_fd == -1) { 90 | fprintf(stderr, "accept(2) failed:%s\n", strerror(errno)); 91 | return 111; 92 | } 93 | ssl = SSL_new(ctx); 94 | SSL_set_fd(ssl, conn_fd); 95 | if (SSL_accept(ssl) == 1) { 96 | SSL_read(ssl, buf, sizeof(buf)); 97 | const char *resp = 98 | "HTTP/1.0 200 OK\r\nContent-Length: 6\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\nhello\n"; 99 | SSL_write(ssl, resp, strlen(resp)); 100 | SSL_shutdown(ssl); 101 | } else { 102 | fprintf(stderr, "SSL_accept failed\n"); 103 | } 104 | SSL_free(ssl); 105 | close(conn_fd); 106 | } 107 | } 108 | 109 | int main(int argc, char **argv) 110 | { 111 | unsigned short port; 112 | SSL_CTX *ctx; 113 | neverbleed_t nb; 114 | char errbuf[NEVERBLEED_ERRBUF_SIZE]; 115 | int use_privsep; 116 | 117 | /* initialization */ 118 | /* FIXME: These APIs are deprecated in favor of OPENSSL_init_crypto in 1.1.0. */ 119 | SSL_load_error_strings(); 120 | SSL_library_init(); 121 | OpenSSL_add_all_algorithms(); 122 | if (neverbleed_init(&nb, errbuf) != 0) { 123 | fprintf(stderr, "openssl_privsep_init: %s\n", errbuf); 124 | return 111; 125 | } 126 | ctx = SSL_CTX_new(SSLv23_server_method()); 127 | SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION); 128 | #ifdef NEVERBLEED_TEST_ECDSA 129 | setup_ecc_key(ctx); 130 | #endif 131 | 132 | /* parse args */ 133 | if (argc != 5) { 134 | fprintf(stderr, "Usage: %s \n", argv[0]); 135 | return 111; 136 | } 137 | if (strcmp(argv[1], "internal") == 0) { 138 | use_privsep = 0; 139 | } else if (strcmp(argv[1], "privsep") == 0) { 140 | use_privsep = 1; 141 | } else { 142 | fprintf(stderr, "unknown mode:%s\n", argv[1]); 143 | return 111; 144 | } 145 | if (sscanf(argv[2], "%hu", &port) != 1) { 146 | fprintf(stderr, "failed to parse port:%s\n", argv[2]); 147 | return 111; 148 | } 149 | if (SSL_CTX_use_certificate_chain_file(ctx, argv[3]) != 1) { 150 | fprintf(stderr, "failed to load certificate chain file:%s\n", argv[3]); 151 | return 111; 152 | } 153 | if (use_privsep) { 154 | if (neverbleed_load_private_key_file(&nb, ctx, argv[4], errbuf) != 1) { 155 | fprintf(stderr, "failed to load private key from file:%s:%s\n", argv[4], errbuf); 156 | return 111; 157 | } 158 | } else { 159 | if (SSL_CTX_use_PrivateKey_file(ctx, argv[4], SSL_FILETYPE_PEM) != 1) { 160 | fprintf(stderr, "failed to load private key from file:%s\n", argv[4]); 161 | return 111; 162 | } 163 | } 164 | 165 | /* start the httpd */ 166 | return dumb_https_server(port, ctx); 167 | } 168 | --------------------------------------------------------------------------------