Apache HTTPD
ssl_engine_pphrase.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* _ _
18 * _ __ ___ ___ __| | ___ ___| | mod_ssl
19 * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
20 * | | | | | | (_) | (_| | \__ \__ \ |
21 * |_| |_| |_|\___/ \__,_|___|___/___/_|
22 * |_____|
23 * ssl_engine_pphrase.c
24 * Pass Phrase Dialog
25 */
26 /* ``Treat your password like your
27 toothbrush. Don't let anybody
28 else use it, and get a new one
29 every six months.''
30 -- Clifford Stoll */
31#include "ssl_private.h"
32
33#include <openssl/ui.h>
34#if MODSSL_HAVE_OPENSSL_STORE
35#include <openssl/store.h>
36#endif
37
50
51#ifdef HAVE_ECC
52static const char *key_types[] = {"RSA", "DSA", "ECC"};
53#else
54static const char *key_types[] = {"RSA", "DSA"};
55#endif
56
57/*
58 * Return true if the named file exists and is readable
59 */
60
63{
67
69 return stat;
70
71 if (sbuf.filetype != APR_REG)
72 return APR_EGENERAL;
73
75 return stat;
76
77 if (mtime) {
78 *mtime = sbuf.mtime;
79 }
80
82 return APR_SUCCESS;
83}
84
85/*
86 * reuse vhost keys for asn1 tables where keys are allocated out
87 * of s->process->pool to prevent "leaking" each time we format
88 * a vhost key. since the key is stored in a table with lifetime
89 * of s->process->pool, the key needs to have the same lifetime.
90 *
91 * XXX: probably seems silly to use a hash table with keys and values
92 * being the same, but it is easier than doing a linear search
93 * and will make it easier to remove keys if needed in the future.
94 * also have the problem with apr_array_header_t that if we
95 * underestimate the number of vhost keys when we apr_array_make(),
96 * the array will get resized when we push past the initial number
97 * of elts. this resizing in the s->process->pool means "leaking"
98 * since apr_array_push() will apr_alloc arr->nalloc * 2 elts,
99 * leaving the original arr->elts to waste.
100 */
102 const char *id, int i)
103{
104 /* 'p' pool used here is cleared on restarts (or sooner) */
105 char *key = apr_psprintf(p, "%s:%d", id, i);
106 void *keyptr = apr_hash_get(mc->tVHostKeys, key,
108
109 if (!keyptr) {
110 /* make a copy out of s->process->pool */
111 keyptr = apr_pstrdup(mc->pPool, key);
112 apr_hash_set(mc->tVHostKeys, keyptr,
113 APR_HASH_KEY_STRING, keyptr);
114 }
115
116 return (char *)keyptr;
117}
118
119/* _________________________________________________________________
120**
121** Pass Phrase and Private Key Handling
122** _________________________________________________________________
123*/
124
125#define BUILTIN_DIALOG_BACKOFF 2
126#define BUILTIN_DIALOG_RETRIES 5
127
130
131int ssl_pphrase_Handle_CB(char *, int, int, void *);
132
134{
135 if ((idx < 0) || (idx >= arr->nelts)) {
136 return NULL;
137 }
138
139 return ((char **)arr->elts)[idx];
140}
141
143 const char *pkey_file,
145{
148 const char *key_id = asn1_table_vhost_key(mc, p, sc->vhost_id, idx);
151 int nPassPhrase = (*pphrases)->nelts;
152 int nPassPhraseRetry = 0;
154 apr_status_t rv;
156
157 if (!pkey_file) {
159 "Init: No private key specified for %s", key_id);
160 return ssl_die(s);
161 }
162 else if ((rv = exists_and_readable(pkey_file, p, &pkey_mtime))
163 != APR_SUCCESS ) {
165 "Init: Can't open server private key file %s", pkey_file);
166 return ssl_die(s);
167 }
168
169 ppcb_arg.s = s;
170 ppcb_arg.p = p;
171 ppcb_arg.aPassPhrase = *pphrases;
172 ppcb_arg.nPassPhraseCur = 0;
173 ppcb_arg.cpPassPhraseCur = NULL;
174 ppcb_arg.nPassPhraseDialog = 0;
175 ppcb_arg.nPassPhraseDialogCur = 0;
176 ppcb_arg.bPassPhraseDialogOnce = TRUE;
177 ppcb_arg.key_id = key_id;
178 ppcb_arg.pkey_file = pkey_file;
179
180 /*
181 * if the private key is encrypted and SSLPassPhraseDialog
182 * is configured to "builtin" it isn't possible to prompt for
183 * a password after httpd has detached from the tty.
184 * in this case if we already have a private key and the
185 * file name/mtime hasn't changed, then reuse the existing key.
186 * we also reuse existing private keys that were encrypted for
187 * exec: and pipe: dialogs to minimize chances to snoop the
188 * password. that and pipe: dialogs might prompt the user
189 * for password, which on win32 for example could happen 4
190 * times at startup. twice for each child and twice within
191 * each since apache "restarts itself" on startup.
192 * of course this will not work for the builtin dialog if
193 * the server was started without LoadModule ssl_module
194 * configured, then restarted with it configured.
195 * but we fall through with a chance of success if the key
196 * is not encrypted or can be handled via exec or pipe dialog.
197 * and in the case of fallthrough, pkey_mtime and isatty()
198 * are used to give a better idea as to what failed.
199 */
200 if (pkey_mtime) {
201 ssl_asn1_t *asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id);
202 if (asn1 && (asn1->source_mtime == pkey_mtime)) {
204 "Reusing existing private key from %s on restart",
205 ppcb_arg.pkey_file);
206 return APR_SUCCESS;
207 }
208 }
209
211 "Attempting to load encrypted (?) private key %s", key_id);
212
213 for (;;) {
214 /*
215 * Try to read the private key file with the help of
216 * the callback function which serves the pass
217 * phrases to OpenSSL
218 */
219
220 ppcb_arg.cpPassPhraseCur = NULL;
221
222 /* Ensure that the error stack is empty; some SSL
223 * functions will fail spuriously if the error stack
224 * is not empty. */
226
229 /* If the private key was successfully read, nothing more to
230 do here. */
231 if (pPrivateKey != NULL)
232 break;
233
234 /*
235 * when we have more remembered pass phrases
236 * try to reuse these first.
237 */
238 if (ppcb_arg.nPassPhraseCur < nPassPhrase) {
239 ppcb_arg.nPassPhraseCur++;
240 continue;
241 }
242
243 /*
244 * else it's not readable and we have no more
245 * remembered pass phrases. Then this has to mean
246 * that the callback function popped up the dialog
247 * but a wrong pass phrase was entered. We give the
248 * user (but not the dialog program) a few more
249 * chances...
250 */
251#ifndef WIN32
254#else
256#endif
257 && ppcb_arg.cpPassPhraseCur != NULL
259 apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect "
260 "(%d more retr%s permitted).\n",
261 (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry),
262 (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry) == 1 ? "y" : "ies");
263 nPassPhraseRetry++;
264 if (nPassPhraseRetry > BUILTIN_DIALOG_BACKOFF)
265 apr_sleep((nPassPhraseRetry-BUILTIN_DIALOG_BACKOFF)
266 * 5 * APR_USEC_PER_SEC);
267 continue;
268 }
271 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02577)
272 "Init: SSLPassPhraseDialog builtin is not "
273 "supported on Win32 (key file "
274 "%s)", ppcb_arg.pkey_file);
275 return ssl_die(s);
276 }
277#endif /* WIN32 */
278
279 /*
280 * Ok, anything else now means a fatal error.
281 */
282 if (ppcb_arg.cpPassPhraseCur == NULL) {
283 if (ppcb_arg.nPassPhraseDialogCur && pkey_mtime &&
284 !isatty(fileno(stdout))) /* XXX: apr_isatty() */
285 {
286 ap_log_error(APLOG_MARK, APLOG_ERR, 0,
287 s, APLOGNO(02578)
288 "Init: Unable to read pass phrase "
289 "[Hint: key introduced or changed "
290 "before restart?]");
291 ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
292 }
293 else {
294 ap_log_error(APLOG_MARK, APLOG_ERR, 0,
295 s, APLOGNO(02579) "Init: Private key not found");
296 ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
297 }
298 if (writetty) {
299 apr_file_printf(writetty, "Apache:mod_ssl:Error: Private key not found.\n");
300 apr_file_printf(writetty, "**Stopped\n");
301 }
302 }
303 else {
305 "Init: Pass phrase incorrect for key %s",
306 key_id);
308
309 if (writetty) {
310 apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect.\n");
311 apr_file_printf(writetty, "**Stopped\n");
312 }
313 }
314 return ssl_die(s);
315 }
316
317 if (pPrivateKey == NULL) {
319 "Init: Unable to read server private key from file %s",
320 ppcb_arg.pkey_file);
322 return ssl_die(s);
323 }
324
325 /*
326 * Log the type of reading
327 */
328 if (ppcb_arg.nPassPhraseDialogCur == 0) {
330 "unencrypted %s private key - pass phrase not "
331 "required", key_id);
332 }
333 else {
334 if (ppcb_arg.cpPassPhraseCur != NULL) {
336 s, APLOGNO(02583)
337 "encrypted %s private key - pass phrase "
338 "requested", key_id);
339 }
340 else {
342 s, APLOGNO(02584)
343 "encrypted %s private key - pass phrase"
344 " reused", key_id);
345 }
346 }
347
348 /*
349 * Ok, when we have one more pass phrase store it
350 */
351 if (ppcb_arg.cpPassPhraseCur != NULL) {
352 *(const char **)apr_array_push(ppcb_arg.aPassPhrase) =
353 ppcb_arg.cpPassPhraseCur;
354 nPassPhrase++;
355 }
356
357 /* Cache the private key in the global module configuration so it
358 * can be used after subsequent reloads. */
359 asn1 = ssl_asn1_table_set(mc->tPrivateKey, key_id, pPrivateKey);
360
361 if (ppcb_arg.nPassPhraseDialogCur != 0) {
362 /* remember mtime of encrypted keys */
363 asn1->source_mtime = pkey_mtime;
364 }
365
366 /*
367 * Free the private key structure
368 */
370
371 /*
372 * Let the user know when we're successful.
373 */
374 if ((ppcb_arg.nPassPhraseDialog > 0) &&
375 (ppcb_arg.cpPassPhraseCur != NULL)) {
376 if (writetty) {
378 "OK: Pass Phrase Dialog successful.\n");
379 }
380 }
381
382 /* Close the pipes if they were opened
383 */
384 if (readtty) {
388 }
389
390 return APR_SUCCESS;
391}
392
394{
395 /* Child process code for 'ErrorLog "|..."';
396 * may want a common framework for this, since I expect it will
397 * be common for other foo-loggers to want this sort of thing...
398 */
400 apr_procattr_t *procattr;
402
403 if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS) &&
404 ((rc = apr_procattr_io_set(procattr,
407 APR_NO_PIPE)) == APR_SUCCESS)) {
408 char **args;
409
411 procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew));
412 rc = apr_proc_create(procnew, args[0], (const char * const *)args,
413 NULL, procattr, p);
414 if (rc == APR_SUCCESS) {
415 /* XXX: not sure if we aught to...
416 * apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
417 */
418 writetty = procnew->in;
419 readtty = procnew->out;
420 }
421 }
422
423 return rc;
424}
425
426static int pipe_get_passwd_cb(char *buf, int length, char *prompt, int verify)
427{
429 char *p;
430
432
433 buf[0]='\0';
436
437 if (rc != APR_SUCCESS || apr_file_eof(readtty)) {
438 memset(buf, 0, length);
439 return 1; /* failure */
440 }
441 if ((p = strchr(buf, '\n')) != NULL) {
442 *p = '\0';
443 }
444#ifdef WIN32
445 /* XXX: apr_sometest */
446 if ((p = strchr(buf, '\r')) != NULL) {
447 *p = '\0';
448 }
449#endif
450 return 0;
451}
452
453int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
454{
457 char *cpp;
458 int len = -1;
459
460 ppcb_arg->nPassPhraseDialog++;
461 ppcb_arg->nPassPhraseDialogCur++;
462
463 /*
464 * When remembered pass phrases are available use them...
465 */
466 if ((cpp = pphrase_array_get(ppcb_arg->aPassPhrase,
467 ppcb_arg->nPassPhraseCur)) != NULL) {
469 len = strlen(buf);
470 return len;
471 }
472
473 /*
474 * Builtin or Pipe dialog
475 */
478 char *prompt;
479 int i;
480
482 if (!readtty) {
484 APLOGNO(01965)
485 "Init: Creating pass phrase dialog pipe child "
486 "'%s'", sc->server->pphrase_dialog_path);
489 != APR_SUCCESS) {
491 APLOGNO(01966)
492 "Init: Failed to create pass phrase pipe '%s'",
496 memset(buf, 0, (unsigned int)bufsize);
497 return (-1);
498 }
499 }
501 "Init: Requesting pass phrase via piped dialog");
502 }
503 else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
504#ifdef WIN32
506 memset(buf, 0, (unsigned int)bufsize);
507 return (-1);
508#else
509 /*
510 * stderr has already been redirected to the error_log.
511 * rather than attempting to temporarily rehook it to the terminal,
512 * we print the prompt to stdout before EVP_read_pw_string turns
513 * off tty echo
514 */
516
518 "Init: Requesting pass phrase via builtin terminal "
519 "dialog");
520#endif
521 }
522
523 /*
524 * The first time display a header to inform the user about what
525 * program he actually speaks to, which module is responsible for
526 * this terminal dialog and why to the hell he has to enter
527 * something...
528 */
529 if (ppcb_arg->nPassPhraseDialog == 1) {
530 apr_file_printf(writetty, "%s mod_ssl (Pass Phrase Dialog)\n",
532 apr_file_printf(writetty, "Some of your private key files are encrypted for security reasons.\n");
533 apr_file_printf(writetty, "In order to read them you have to provide the pass phrases.\n");
534 }
535 if (ppcb_arg->bPassPhraseDialogOnce) {
536 ppcb_arg->bPassPhraseDialogOnce = FALSE;
538 apr_file_printf(writetty, "Private key %s (%s)\n",
539 ppcb_arg->key_id, ppcb_arg->pkey_file);
540 }
541
542 /*
543 * Emulate the OpenSSL internal pass phrase dialog
544 * (see crypto/pem/pem_lib.c:def_callback() for details)
545 */
546 prompt = "Enter pass phrase:";
547
548 for (;;) {
552 }
553 else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
555 }
556 if (i != 0) {
558 memset(buf, 0, (unsigned int)bufsize);
559 return (-1);
560 }
561 len = strlen(buf);
562 if (len < 1)
563 apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase empty (needs to be at least 1 character).\n");
564 else
565 break;
566 }
567 }
568
569 /*
570 * Filter program
571 */
573 const char *cmd = sc->server->pphrase_dialog_path;
574 const char **argv = apr_palloc(ppcb_arg->p, sizeof(char *) * 4);
575 const char *idx = ap_strrchr_c(ppcb_arg->key_id, ':') + 1;
576 char *result;
577 int i;
578
580 "Init: Requesting pass phrase from dialog filter "
581 "program (%s)", cmd);
582
583 argv[0] = cmd;
584 argv[1] = apr_pstrndup(ppcb_arg->p, ppcb_arg->key_id,
585 idx-1 - ppcb_arg->key_id);
586 if ((i = atoi(idx)) < CERTKEYS_IDX_MAX+1) {
587 /*
588 * For compatibility with existing 2.4.x configurations, use
589 * "RSA", "DSA" and "ECC" strings for the first two/three keys
590 */
591 argv[2] = key_types[i];
592 } else {
593 /* Four and above: use the integer index */
594 argv[2] = apr_pstrdup(ppcb_arg->p, idx);
595 }
596 argv[3] = NULL;
597
600 len = strlen(buf);
601 }
602
603 /*
604 * Ok, we now have the pass phrase, so give it back
605 */
606 ppcb_arg->cpPassPhraseCur = apr_pstrdup(ppcb_arg->p, buf);
607
608 /*
609 * And return its length to OpenSSL...
610 */
611 return (len);
612}
613
614#if MODSSL_HAVE_ENGINE_API || MODSSL_HAVE_OPENSSL_STORE
615
616/* OpenSSL UI implementation for passphrase entry; largely duplicated
617 * from ssl_pphrase_Handle_CB but adjusted for UI API. TODO: Might be
618 * worth trying to shift pphrase handling over to the UI API
619 * completely. */
620static int passphrase_ui_open(UI *ui)
621{
624
625 ppcb->nPassPhraseDialog++;
626 ppcb->nPassPhraseDialogCur++;
627
628 /*
629 * Builtin or Pipe dialog
630 */
634 if (!readtty) {
636 APLOGNO(10143)
637 "Init: Creating pass phrase dialog pipe child "
638 "'%s'", sc->server->pphrase_dialog_path);
641 != APR_SUCCESS) {
643 APLOGNO(10144)
644 "Init: Failed to create pass phrase pipe '%s'",
646 return 0;
647 }
648 }
650 "Init: Requesting pass phrase via piped dialog");
651 }
652 else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
653#ifdef WIN32
655 "Init: Failed to create pass phrase pipe '%s'",
657 return 0;
658#else
659 /*
660 * stderr has already been redirected to the error_log.
661 * rather than attempting to temporarily rehook it to the terminal,
662 * we print the prompt to stdout before EVP_read_pw_string turns
663 * off tty echo
664 */
666
668 "Init: Requesting pass phrase via builtin terminal "
669 "dialog");
670#endif
671 }
672
673 /*
674 * The first time display a header to inform the user about what
675 * program he actually speaks to, which module is responsible for
676 * this terminal dialog and why to the hell he has to enter
677 * something...
678 */
679 if (ppcb->nPassPhraseDialog == 1) {
680 apr_file_printf(writetty, "%s mod_ssl (Pass Phrase Dialog)\n",
683 "A pass phrase is required to access the private key.\n");
684 }
685 if (ppcb->bPassPhraseDialogOnce) {
686 ppcb->bPassPhraseDialogOnce = FALSE;
688 apr_file_printf(writetty, "Private key %s (%s)\n",
689 ppcb->key_id, ppcb->pkey_file);
690 }
691 }
692
693 return 1;
694}
695
696static int passphrase_ui_read(UI *ui, UI_STRING *uis)
697{
700 const char *prompt;
701 int i;
702 int bufsize;
703 int len;
704 char *buf;
705
707 if (prompt == NULL) {
708 prompt = "Enter pass phrase:";
709 }
710
711 /*
712 * Get the maximum expected size and allocate the buffer
713 */
716
719 /*
720 * Get the pass phrase through a callback.
721 * Empty input is not accepted.
722 */
723 for (;;) {
726 }
727 else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
729 }
730 if (i != 0) {
732 return 0;
733 }
734 len = strlen(buf);
735 if (len < 1){
736 apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase"
737 "empty (needs to be at least 1 character).\n");
739 }
740 else {
741 break;
742 }
743 }
744 }
745 /*
746 * Filter program
747 */
749 const char *cmd = sc->server->pphrase_dialog_path;
750 const char **argv = apr_palloc(ppcb->p, sizeof(char *) * 3);
751 char *result;
752
754 "Init: Requesting pass phrase from dialog filter "
755 "program (%s)", cmd);
756
757 argv[0] = cmd;
758 argv[1] = ppcb->key_id;
759 argv[2] = NULL;
760
763 len = strlen(buf);
764 }
765
766 /*
767 * Ok, we now have the pass phrase, so give it back
768 */
769 ppcb->cpPassPhraseCur = apr_pstrdup(ppcb->p, buf);
771
772 /* Clear sensitive data. */
774 return 1;
775}
776
778{
780 SSLSrvConfigRec *sc;
781 const char *prompt;
782
783 sc = mySrvConfig(ppcb->s);
784
789 }
790
791 return 1;
792}
793
794static int passphrase_ui_close(UI *ui)
795{
796 /*
797 * Close the pipes if they were opened
798 */
799 if (readtty) {
803 }
804 return 1;
805}
806
808{
809 UI_METHOD *uim = uip;
810
812
813 return APR_SUCCESS;
814}
815
817{
818 UI_METHOD *ui_method = UI_create_method("Passphrase UI");
819
824
827
828 return ui_method;
829}
830#endif
831
832#if MODSSL_HAVE_ENGINE_API
834{
835 ENGINE *e = engine;
836
838
839 return APR_SUCCESS;
840}
841
843 apr_pool_t *ptemp,
844 const char *vhostid,
845 const char *certid,
846 const char *keyid,
847 X509 **pubkey,
849{
850 const char *c, *scheme;
851 ENGINE *e;
854
855 memset(&ppcb, 0, sizeof ppcb);
856 ppcb.s = s;
857 ppcb.p = ptemp;
858 ppcb.bPassPhraseDialogOnce = TRUE;
859 ppcb.key_id = vhostid;
860 ppcb.pkey_file = keyid;
861
862 c = ap_strchr_c(keyid, ':');
863 if (!c || c == keyid) {
865 "Init: Unrecognized private key identifier `%s'",
866 keyid);
867 return ssl_die(s);
868 }
869
870 scheme = apr_pstrmemdup(ptemp, keyid, c - keyid);
871 if (!(e = ENGINE_by_id(scheme))) {
873 "Init: Failed to load engine for private key %s",
874 keyid);
876 return ssl_die(s);
877 }
878
879 if (!ENGINE_init(e)) {
881 "Init: Failed to initialize engine %s for private key %s",
882 scheme, keyid);
884 return ssl_die(s);
885 }
886
888 "Init: Initialized engine %s for private key %s",
889 scheme, keyid);
890
891 if (APLOGdebug(s)) {
892 ENGINE_ctrl_cmd_string(e, "VERBOSE", NULL, 0);
893 }
894
895 if (certid) {
896 struct {
897 const char *cert_id;
898 X509 *cert;
899 } params = { certid, NULL };
900
901 if (!ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &params, NULL, 1)) {
903 "Init: Unable to get the certificate");
905 return ssl_die(s);
906 }
907
908 *pubkey = params.cert;
909 }
910
912 if (*privkey == NULL) {
914 "Init: Unable to get the private key");
916 return ssl_die(s);
917 }
918
919 /* Release the functional reference obtained by ENGINE_init() only
920 * when after the ENGINE is no longer used. */
922
923 /* Release the structural reference obtained by ENGINE_by_id()
924 * immediately. */
925 ENGINE_free(e);
926
927 return APR_SUCCESS;
928}
929#endif
930
931#if MODSSL_HAVE_OPENSSL_STORE
933 const char *vhostid,
934 const char *uri, int info_type)
935{
940
941 memset(&ppcb, 0, sizeof ppcb);
942 ppcb.s = s;
943 ppcb.p = p;
944 ppcb.bPassPhraseDialogOnce = TRUE;
945 ppcb.key_id = vhostid;
946 ppcb.pkey_file = uri;
947
949 if (!sctx) {
951 "Init: OSSL_STORE_open failed for PKCS#11 URI `%s'",
952 uri);
953 return NULL;
954 }
955
956 while (!OSSL_STORE_eof(sctx)) {
958 if (!info)
959 break;
960
962 break;
963
965 info = NULL;
966 }
967
969
970 return info;
971}
972
974 const char *vhostid,
975 const char *certid,
976 const char *keyid,
977 X509 **pubkey,
979{
981
982 *privkey = NULL;
983 *pubkey = NULL;
984
986 if (!info) {
988 "Init: OSSL_STORE_INFO_PKEY lookup failed for private key identifier `%s'",
989 keyid);
990 return ssl_die(s);
991 }
992
995 if (!*privkey) {
997 "Init: OSSL_STORE_INFO_PKEY lookup failed for private key identifier `%s'",
998 keyid);
999 return ssl_die(s);
1000 }
1001
1002 if (certid) {
1004 if (!info) {
1006 "Init: OSSL_STORE_INFO_CERT lookup failed for certificate identifier `%s'",
1007 keyid);
1008 return ssl_die(s);
1009 }
1010
1013 if (!*pubkey) {
1015 "Init: OSSL_STORE_INFO_CERT lookup failed for certificate identifier `%s'",
1016 certid);
1017 return ssl_die(s);
1018 }
1019 }
1020
1021 return APR_SUCCESS;
1022}
1023#endif
1024
1026 apr_pool_t *pconf, apr_pool_t *ptemp,
1027 const char *vhostid,
1028 const char *certid, const char *keyid,
1030{
1031#if MODSSL_HAVE_ENGINE_API
1033
1034 /* For OpenSSL 3.x, use the STORE-based API if either ENGINE
1035 * support was not present compile-time, or if it's built but
1036 * SSLCryptoDevice is not configured. */
1037 if (mc->szCryptoDevice)
1038 return modssl_load_keypair_engine(s, pconf, ptemp,
1039 vhostid, certid, keyid,
1040 pubkey, privkey);
1041#endif
1042#if MODSSL_HAVE_OPENSSL_STORE
1043 return modssl_load_keypair_store(s, ptemp, vhostid, certid, keyid,
1044 pubkey, privkey);
1045#else
1047 "Init: no method for loading keypair for %s (%s | %s)",
1048 vhostid, certid ? certid : "no cert", keyid);
1049 return APR_ENOTIMPL;
1050#endif
1051}
const char apr_size_t len
Definition ap_regex.h:187
#define AP_SERVER_BASEVERSION
Definition ap_release.h:75
#define TRUE
Definition abts.h:38
#define FALSE
Definition abts.h:35
if(!found)
Definition core.c:2803
static apr_pool_t * pconf
Definition event.c:441
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_INFO
Definition http_log.h:70
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOGdebug(s)
Definition http_log.h:234
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_EMERG
Definition http_log.h:64
#define APLOG_DEBUG
Definition http_log.h:71
const unsigned char * buf
Definition util_md5.h:50
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_ENOTIMPL
Definition apr_errno.h:476
apr_bucket * e
apr_file_t * fd
int apr_off_t * length
apr_pool_t const char * params
Definition apr_dbd.h:141
apr_memcache_t * mc
apr_redis_t * rc
Definition apr_redis.h:173
const char * uri
Definition apr_uri.h:159
apr_status_t ssl_die(server_rec *s)
#define SSLLOG_MARK
char * ssl_util_readfilter(server_rec *, apr_pool_t *, const char *, const char *const *)
Definition ssl_util.c:151
apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *pconf, apr_pool_t *ptemp, const char *vhostid, const char *certid, const char *keyid, X509 **pubkey, EVP_PKEY **privkey)
#define mySrvConfig(srv)
apr_status_t ssl_load_encrypted_pkey(server_rec *s, apr_pool_t *p, int idx, const char *pkey_file, apr_array_header_t **pphrases)
ssl_asn1_t * ssl_asn1_table_set(apr_hash_t *table, const char *key, EVP_PKEY *pkey)
Definition ssl_util.c:199
#define myModConfig(srv)
void ssl_log_ssl_error(const char *file, int line, int level, server_rec *s)
ssl_asn1_t * ssl_asn1_table_get(apr_hash_t *table, const char *key)
Definition ssl_util.c:228
#define BOOL
Definition ssl_private.h:81
#define CERTKEYS_IDX_MAX
@ SSL_PPTYPE_PIPE
@ SSL_PPTYPE_BUILTIN
@ SSL_PPTYPE_FILTER
EVP_PKEY * modssl_read_privatekey(const char *filename, pem_password_cb *cb, void *s)
#define ap_strrchr_c(s, c)
Definition httpd.h:2357
#define ap_strchr_c(s, c)
Definition httpd.h:2353
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
char apr_size_t bufsize
Definition apr_errno.h:53
int apr_status_t
Definition apr_errno.h:44
@ APR_REG
const char * key
apr_time_t mtime
#define APR_READ
Definition apr_file_io.h:93
#define APR_FINFO_MIN
const char * fname
apr_array_header_t ** result
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
apr_vformatter_buff_t * c
Definition apr_lib.h:175
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
const apr_array_header_t * arr
Definition apr_tables.h:187
#define APR_FULL_BLOCK
apr_cmdtype_e cmd
const char const char *const * args
#define APR_NO_PIPE
const char * progname
apr_int64_t apr_time_t
Definition apr_time.h:45
apr_pool_t * p
Definition md_event.c:32
const char * argv[3]
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
static const char * asn1_table_vhost_key(SSLModConfigRec *mc, apr_pool_t *p, const char *id, int i)
int ssl_pphrase_Handle_CB(char *, int, int, void *)
static apr_status_t exists_and_readable(const char *fname, apr_pool_t *pool, apr_time_t *mtime)
static apr_status_t ssl_pipe_child_create(apr_pool_t *p, const char *progname)
static char * pphrase_array_get(apr_array_header_t *arr, int idx)
static int pipe_get_passwd_cb(char *buf, int length, char *prompt, int verify)
static const char * key_types[]
static apr_file_t * readtty
static apr_file_t * writetty
#define BUILTIN_DIALOG_RETRIES
Internal interfaces private to mod_ssl.
const char * vhost_id
modssl_ctx_t * server
ssl_pphrase_t pphrase_dialog_type
const char * pphrase_dialog_path
unsigned int bPassPhraseDialogOnce
apr_array_header_t * aPassPhrase
A structure to store information for each virtual server.
Definition httpd.h:1322
INT info