2 * PKI related functions
4 * Copyright (C) 2007 Olaf Kirch <olaf.kirch@oracle.com>
11 #include <openssl/pem.h>
12 #include <openssl/err.h>
21 /* versions prior to 9.6.8 didn't seem to have these */
22 #if OPADDRCONFIGENSSL_VERSION_NUMBER < 0x00906080L
23 # define EVP_MD_CTX_init(c) do { } while (0)
24 # define EVP_MD_CTX_cleanup(c) do { } while (0)
26 #if OPADDRCONFIGENSSL_VERSION_NUMBER < 0x00906070L
27 # define i2d_DSA_PUBKEY i2d_DSA_PUBKEY_backwards
29 static int i2d_DSA_PUBKEY_backwards(DSA
*, unsigned char **);
32 static int isns_openssl_init
= 0;
34 static int isns_dsasig_verify(isns_security_t
*ctx
,
35 isns_principal_t
*peer
,
37 const struct isns_authblk
*);
38 static int isns_dsasig_sign(isns_security_t
*ctx
,
39 isns_principal_t
*peer
,
41 struct isns_authblk
*);
42 static EVP_PKEY
*isns_dsasig_load_private_pem(isns_security_t
*ctx
,
43 const char *filename
);
44 static EVP_PKEY
*isns_dsasig_load_public_pem(isns_security_t
*ctx
,
45 const char *filename
);
46 static DSA
* isns_dsa_load_params(const char *);
50 * Create a DSA security context
53 isns_create_dsa_context(void)
57 if (!isns_openssl_init
) {
58 ERR_load_crypto_strings();
59 OpenSSL_add_all_algorithms();
60 OpenSSL_add_all_ciphers();
61 OpenSSL_add_all_digests();
62 isns_openssl_init
= 1;
65 ctx
= isns_calloc(1, sizeof(*ctx
));
68 ctx
->is_type
= ISNS_AUTH_TYPE_SHA1_DSA
;
69 ctx
->is_replay_window
= isns_config
.ic_auth
.replay_window
;
70 ctx
->is_timestamp_jitter
= isns_config
.ic_auth
.timestamp_jitter
;
72 ctx
->is_verify
= isns_dsasig_verify
;
73 ctx
->is_sign
= isns_dsasig_sign
;
74 ctx
->is_load_private
= isns_dsasig_load_private_pem
;
75 ctx
->is_load_public
= isns_dsasig_load_public_pem
;
77 isns_debug_auth("Created DSA authentication context\n");
82 * DSA signature generation and verification
85 isns_message_digest(EVP_MD_CTX
*md
, const buf_t
*pdu
,
86 const struct isns_authblk
*blk
)
90 EVP_DigestUpdate(md
, buf_head(pdu
), buf_avail(pdu
));
92 /* The RFC doesn't say which pieces of the
93 * message should be hashed.
94 * We make an educated guess.
96 stamp
= htonll(blk
->iab_timestamp
);
97 EVP_DigestUpdate(md
, &stamp
, sizeof(stamp
));
101 isns_dsasig_report_errors(const char *msg
, isns_print_fn_t
*fn
)
105 fn("%s - OpenSSL errors follow:\n", msg
);
106 while ((code
= ERR_get_error()) != 0)
108 ERR_func_error_string(code
),
109 ERR_reason_error_string(code
));
113 isns_dsasig_sign(isns_security_t
*ctx
,
114 isns_principal_t
*peer
,
116 struct isns_authblk
*blk
)
118 static unsigned char signature
[1024];
119 unsigned int sig_len
= sizeof(signature
);
124 if ((pkey
= peer
->is_key
) == NULL
)
127 if (pkey
->type
!= EVP_PKEY_DSA
) {
129 "Incompatible public key (spi=%s)\n",
133 if (EVP_PKEY_size(pkey
) > sizeof(signature
)) {
134 isns_error("isns_dsasig_sign: signature buffer too small\n");
137 if (pkey
->pkey
.dsa
->priv_key
== NULL
) {
138 isns_error("isns_dsasig_sign: oops, seems to be a public key\n");
142 isns_debug_auth("Signing messages with spi=%s, DSA/%u\n",
143 peer
->is_name
, EVP_PKEY_bits(pkey
));
145 EVP_MD_CTX_init(&md_ctx
);
146 EVP_SignInit(&md_ctx
, EVP_dss1());
147 isns_message_digest(&md_ctx
, pdu
, blk
);
148 err
= EVP_SignFinal(&md_ctx
,
151 EVP_MD_CTX_cleanup(&md_ctx
);
154 isns_dsasig_report_errors("EVP_SignFinal failed", isns_error
);
158 blk
->iab_sig
= signature
;
159 blk
->iab_sig_len
= sig_len
;
164 isns_dsasig_verify(isns_security_t
*ctx
,
165 isns_principal_t
*peer
,
167 const struct isns_authblk
*blk
)
173 if ((pkey
= peer
->is_key
) == NULL
)
176 if (pkey
->type
!= EVP_PKEY_DSA
) {
178 "Incompatible public key (spi=%s)\n",
183 EVP_MD_CTX_init(&md_ctx
);
184 EVP_VerifyInit(&md_ctx
, EVP_dss1());
185 isns_message_digest(&md_ctx
, pdu
, blk
);
186 err
= EVP_VerifyFinal(&md_ctx
,
187 blk
->iab_sig
, blk
->iab_sig_len
,
189 EVP_MD_CTX_cleanup(&md_ctx
);
192 isns_debug_auth("*** Incorrect signature ***\n");
196 isns_dsasig_report_errors("EVP_VerifyFinal failed", isns_error
);
200 isns_debug_message("Good signature from %s\n",
201 peer
->is_name
?: "<server>");
206 isns_dsasig_load_private_pem(isns_security_t
*ctx
, const char *filename
)
211 if (!(fp
= fopen(filename
, "r"))) {
212 isns_error("Unable to open DSA keyfile %s: %m\n",
217 pkey
= PEM_read_PrivateKey(fp
, NULL
, NULL
, NULL
);
223 isns_dsasig_load_public_pem(isns_security_t
*ctx
, const char *filename
)
228 if (!(fp
= fopen(filename
, "r"))) {
229 isns_error("Unable to open DSA keyfile %s: %m\n",
234 pkey
= PEM_read_PUBKEY(fp
, NULL
, NULL
, NULL
);
236 isns_dsasig_report_errors("Error loading DSA public key",
245 isns_dsa_decode_public(const void *ptr
, size_t len
)
247 const unsigned char *der
= ptr
;
251 /* Assigning ptr to a temporary variable avoids a silly
252 * compiled warning about type-punning. */
253 dsa
= d2i_DSA_PUBKEY(NULL
, &der
, len
);
257 evp
= EVP_PKEY_new();
258 EVP_PKEY_assign_DSA(evp
, dsa
);
263 isns_dsa_encode_public(EVP_PKEY
*pkey
, void **ptr
, size_t *len
)
268 bytes
= i2d_DSA_PUBKEY(pkey
->pkey
.dsa
, (unsigned char **) ptr
);
277 isns_dsa_load_public(const char *name
)
279 return isns_dsasig_load_public_pem(NULL
, name
);
283 isns_dsa_store_private(const char *name
, EVP_PKEY
*key
)
288 if ((fd
= open(name
, O_WRONLY
|O_CREAT
|O_EXCL
, 0600)) < 0) {
289 isns_error("Cannot save DSA key to %s: %m\n", name
);
293 if (!(fp
= fdopen(fd
, "w"))) {
294 isns_error("fdopen(%s): %m\n", name
);
299 rv
= PEM_write_PrivateKey(fp
, key
, NULL
, NULL
, 0, 0, NULL
);
303 isns_dsasig_report_errors("Failed to store private key",
310 isns_dsa_store_public(const char *name
, EVP_PKEY
*key
)
315 if (!(fp
= fopen(name
, "w"))) {
316 isns_error("Unable to open %s: %m\n", name
);
320 rv
= PEM_write_PUBKEY(fp
, key
);
324 isns_dsasig_report_errors("Failed to store public key",
335 isns_dsa_generate_key(void)
340 if (!(dsa
= isns_dsa_load_params(isns_config
.ic_dsa
.param_file
)))
343 if (!DSA_generate_key(dsa
)) {
344 isns_dsasig_report_errors("Failed to generate DSA key",
349 pkey
= EVP_PKEY_new();
350 EVP_PKEY_assign_DSA(pkey
, dsa
);
360 isns_dsa_load_params(const char *filename
)
366 isns_error("Cannot generate key - no DSA parameter file\n");
369 if (!(fp
= fopen(filename
, "r"))) {
370 isns_error("Unable to open %s: %m\n", filename
);
374 dsa
= PEM_read_DSAparams(fp
, NULL
, NULL
, NULL
);
378 isns_dsasig_report_errors("Error loading DSA parameters",
386 isns_dsa_param_gen_callback(int stage
, int index
, void *dummy
)
397 isns_dsa_init_params(const char *filename
)
402 if (access(filename
, R_OK
) == 0)
405 isns_mkdir_recursive(isns_dirname(filename
));
406 if (!(fp
= fopen(filename
, "w"))) {
407 isns_error("Unable to open %s: %m\n", filename
);
411 isns_notice("Generating DSA parameters; this may take a while\n");
412 dsa
= DSA_generate_parameters(1024, NULL
, 0,
413 NULL
, NULL
, isns_dsa_param_gen_callback
, NULL
);
417 isns_dsasig_report_errors("Error generating DSA parameters",
423 if (!PEM_write_DSAparams(fp
, dsa
)) {
424 isns_dsasig_report_errors("Error writing DSA parameters",
436 * Make sure the authentication key is present.
439 isns_dsa_init_key(const char *filename
)
441 char pubkey_path
[1024];
444 isns_mkdir_recursive(isns_dirname(filename
));
445 snprintf(pubkey_path
, sizeof(pubkey_path
),
447 if (access(filename
, R_OK
) == 0
448 && access(pubkey_path
, R_OK
) == 0)
451 if (!(pkey
= isns_dsa_generate_key())) {
452 isns_error("Failed to generate AuthKey\n");
456 if (!isns_dsa_store_private(filename
, pkey
)) {
457 isns_error("Unable to write private key to %s\n", filename
);
460 isns_notice("Stored private key in %s\n", filename
);
462 if (!isns_dsa_store_public(pubkey_path
, pkey
)) {
463 isns_error("Unable to write public key to %s\n", pubkey_path
);
466 isns_notice("Stored private key in %s\n", pubkey_path
);
472 * Simple keystore - this is a flat directory, with
473 * public key files using the SPI as their name.
475 typedef struct isns_simple_keystore isns_simple_keystore_t
;
476 struct isns_simple_keystore
{
477 isns_keystore_t sc_base
;
482 * Load a DSA key from the cert store
483 * In fact, this will load RSA keys as well.
486 __isns_simple_keystore_find(isns_keystore_t
*store_base
,
487 const char *name
, size_t namelen
)
489 isns_simple_keystore_t
*store
= (isns_simple_keystore_t
*) store_base
;
490 char pathname
[PATH_MAX
];
492 /* Refuse to open key files with names
493 * that refer to parent directories */
494 if (memchr(name
, '/', namelen
) || name
[0] == '.')
497 snprintf(pathname
, sizeof(pathname
),
498 "%s/%.*s", store
->sc_dirpath
,
499 (int) namelen
, name
);
500 if (access(pathname
, R_OK
) < 0)
502 return isns_dsasig_load_public_pem(NULL
, pathname
);
506 isns_create_simple_keystore(const char *dirname
)
508 isns_simple_keystore_t
*store
;
510 store
= isns_calloc(1, sizeof(*store
));
511 store
->sc_base
.ic_name
= "simple key store";
512 store
->sc_base
.ic_find
= __isns_simple_keystore_find
;
513 store
->sc_dirpath
= isns_strdup(dirname
);
515 return (isns_keystore_t
*) store
;
518 #if OPADDRCONFIGENSSL_VERSION_NUMBER < 0x00906070L
519 #undef i2d_DSA_PUBKEY
522 i2d_DSA_PUBKEY_backwards(DSA
*dsa
, unsigned char **ptr
)
527 len
= i2d_DSA_PUBKEY(dsa
, NULL
);
531 *ptr
= buf
= OPENSSL_malloc(len
);
532 return i2d_DSA_PUBKEY(dsa
, &buf
);
536 #endif /* WITH_SECURITY */