doc/man3: use the documented coding style in the example code
Adjust brace placement, whitespace after keywords, indentation and empty lines after variable declarations according to https://www.openssl.org/policies/codingstyle.html. Indent literal sections by exactly one space. Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/1956)
This commit is contained in:
parent
52df25cf2e
commit
2947af32a0
54 changed files with 802 additions and 814 deletions
|
@ -100,14 +100,14 @@ Determine if one time is later or sooner than the current time:
|
|||
int day, sec;
|
||||
|
||||
if (!ASN1_TIME_diff(&day, &sec, NULL, to))
|
||||
/* Invalid time format */
|
||||
/* Invalid time format */
|
||||
|
||||
if (day > 0 || sec > 0)
|
||||
printf("Later\n");
|
||||
printf("Later\n");
|
||||
else if (day < 0 || sec < 0)
|
||||
printf("Sooner\n");
|
||||
printf("Sooner\n");
|
||||
else
|
||||
printf("Same\n");
|
||||
printf("Same\n");
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
|
|
|
@ -262,17 +262,17 @@ The following example demonstrates how to use most of the core async APIs:
|
|||
}
|
||||
|
||||
for (;;) {
|
||||
switch(ASYNC_start_job(&job, ctx, &ret, jobfunc, msg, sizeof(msg))) {
|
||||
switch (ASYNC_start_job(&job, ctx, &ret, jobfunc, msg, sizeof(msg))) {
|
||||
case ASYNC_ERR:
|
||||
case ASYNC_NO_JOBS:
|
||||
printf("An error occurred\n");
|
||||
goto end;
|
||||
printf("An error occurred\n");
|
||||
goto end;
|
||||
case ASYNC_PAUSE:
|
||||
printf("Job was paused\n");
|
||||
break;
|
||||
printf("Job was paused\n");
|
||||
break;
|
||||
case ASYNC_FINISH:
|
||||
printf("Job finished with return value %d\n", ret);
|
||||
goto end;
|
||||
printf("Job finished with return value %d\n", ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Wait for the job to be woken */
|
||||
|
|
|
@ -73,7 +73,7 @@ and not IPv4 addresses mapped to IPv6.
|
|||
These flags are bit flags, so they are to be combined with the
|
||||
C<|> operator, for example:
|
||||
|
||||
BIO_connect(sock, addr, BIO_SOCK_KEEPALIVE | BIO_SOCK_NONBLOCK);
|
||||
BIO_connect(sock, addr, BIO_SOCK_KEEPALIVE | BIO_SOCK_NONBLOCK);
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
|
|
|
@ -65,8 +65,8 @@ data to standard output:
|
|||
bio = BIO_new_fp(stdin, BIO_NOCLOSE);
|
||||
bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
|
||||
BIO_push(b64, bio);
|
||||
while((inlen = BIO_read(b64, inbuf, 512)) > 0)
|
||||
BIO_write(bio_out, inbuf, inlen);
|
||||
while ((inlen = BIO_read(b64, inbuf, 512)) > 0)
|
||||
BIO_write(bio_out, inbuf, inlen);
|
||||
|
||||
BIO_flush(bio_out);
|
||||
BIO_free_all(b64);
|
||||
|
|
|
@ -82,7 +82,8 @@ checking has been omitted for clarity.
|
|||
bio = BIO_new(BIO_s_null());
|
||||
mdtmp = BIO_new(BIO_f_md());
|
||||
BIO_set_md(mdtmp, EVP_sha1());
|
||||
/* For BIO_push() we want to append the sink BIO and keep a note of
|
||||
/*
|
||||
* For BIO_push() we want to append the sink BIO and keep a note of
|
||||
* the start of the chain.
|
||||
*/
|
||||
bio = BIO_push(mdtmp, bio);
|
||||
|
@ -105,8 +106,8 @@ The next example digests data by reading through a chain instead:
|
|||
BIO_set_md(mdtmp, EVP_md5());
|
||||
bio = BIO_push(mdtmp, bio);
|
||||
do {
|
||||
rdlen = BIO_read(bio, buf, sizeof(buf));
|
||||
/* Might want to do something with the data here */
|
||||
rdlen = BIO_read(bio, buf, sizeof(buf));
|
||||
/* Might want to do something with the data here */
|
||||
} while (rdlen > 0);
|
||||
|
||||
This next example retrieves the message digests from a BIO chain and
|
||||
|
@ -118,15 +119,16 @@ outputs them. This could be used with the examples above.
|
|||
int i;
|
||||
mdtmp = bio; /* Assume bio has previously been set up */
|
||||
do {
|
||||
EVP_MD *md;
|
||||
mdtmp = BIO_find_type(mdtmp, BIO_TYPE_MD);
|
||||
if (!mdtmp) break;
|
||||
BIO_get_md(mdtmp, &md);
|
||||
printf("%s digest", OBJ_nid2sn(EVP_MD_type(md)));
|
||||
mdlen = BIO_gets(mdtmp, mdbuf, EVP_MAX_MD_SIZE);
|
||||
for (i = 0; i < mdlen; i++) printf(":%02X", mdbuf[i]);
|
||||
printf("\n");
|
||||
mdtmp = BIO_next(mdtmp);
|
||||
EVP_MD *md;
|
||||
mdtmp = BIO_find_type(mdtmp, BIO_TYPE_MD);
|
||||
if (!mdtmp)
|
||||
break;
|
||||
BIO_get_md(mdtmp, &md);
|
||||
printf("%s digest", OBJ_nid2sn(EVP_MD_type(md)));
|
||||
mdlen = BIO_gets(mdtmp, mdbuf, EVP_MAX_MD_SIZE);
|
||||
for (i = 0; i < mdlen; i++) printf(":%02X", mdbuf[i]);
|
||||
printf("\n");
|
||||
mdtmp = BIO_next(mdtmp);
|
||||
} while (mdtmp);
|
||||
|
||||
BIO_free_all(bio);
|
||||
|
|
|
@ -170,15 +170,15 @@ unencrypted example in L<BIO_s_connect(3)>.
|
|||
exit(1);
|
||||
}
|
||||
if (BIO_do_handshake(sbio) <= 0) {
|
||||
fprintf(stderr, "Error establishing SSL connection\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(1);
|
||||
fprintf(stderr, "Error establishing SSL connection\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* XXX Could examine ssl here to get connection info */
|
||||
|
||||
BIO_puts(sbio, "GET / HTTP/1.0\n\n");
|
||||
for ( ; ; ) {
|
||||
for (;;) {
|
||||
len = BIO_read(sbio, tmpbuf, 1024);
|
||||
if (len <= 0)
|
||||
break;
|
||||
|
@ -261,7 +261,7 @@ a client and also echoes the request to standard output.
|
|||
BIO_puts(sbio, "\r\nConnection Established\r\nRequest headers:\r\n");
|
||||
BIO_puts(sbio, "--------------------------------------------------\r\n");
|
||||
|
||||
for ( ; ; ) {
|
||||
for (;;) {
|
||||
len = BIO_gets(sbio, tmpbuf, 1024);
|
||||
if (len <= 0)
|
||||
break;
|
||||
|
|
|
@ -48,12 +48,13 @@ Traverse a chain looking for digest BIOs:
|
|||
btmp = in_bio; /* in_bio is chain to search through */
|
||||
|
||||
do {
|
||||
btmp = BIO_find_type(btmp, BIO_TYPE_MD);
|
||||
if (btmp == NULL) break; /* Not found */
|
||||
/* btmp is a digest BIO, do something with it ...*/
|
||||
...
|
||||
btmp = BIO_find_type(btmp, BIO_TYPE_MD);
|
||||
if (btmp == NULL)
|
||||
break; /* Not found */
|
||||
/* btmp is a digest BIO, do something with it ...*/
|
||||
...
|
||||
|
||||
btmp = BIO_next(btmp);
|
||||
btmp = BIO_next(btmp);
|
||||
} while (btmp);
|
||||
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@ to retrieve a page and copy the result to standard output.
|
|||
exit(1);
|
||||
}
|
||||
BIO_puts(cbio, "GET / HTTP/1.0\n\n");
|
||||
for ( ; ; ) {
|
||||
for (;;) {
|
||||
len = BIO_read(cbio, tmpbuf, 1024);
|
||||
if (len <= 0)
|
||||
break;
|
||||
|
|
|
@ -92,15 +92,18 @@ Alternative technique:
|
|||
|
||||
BIO *bio_out;
|
||||
bio_out = BIO_new(BIO_s_file());
|
||||
if (bio_out == NULL) /* Error ... */
|
||||
if (!BIO_set_fp(bio_out, stdout, BIO_NOCLOSE)) /* Error ... */
|
||||
if (bio_out == NULL)
|
||||
/* Error */
|
||||
if (!BIO_set_fp(bio_out, stdout, BIO_NOCLOSE))
|
||||
/* Error */
|
||||
BIO_printf(bio_out, "Hello World\n");
|
||||
|
||||
Write to a file:
|
||||
|
||||
BIO *out;
|
||||
out = BIO_new_file("filename.txt", "w");
|
||||
if (!out) /* Error occurred */
|
||||
if (!out)
|
||||
/* Error */
|
||||
BIO_printf(out, "Hello World\n");
|
||||
BIO_free(out);
|
||||
|
||||
|
@ -108,8 +111,10 @@ Alternative technique:
|
|||
|
||||
BIO *out;
|
||||
out = BIO_new(BIO_s_file());
|
||||
if (out == NULL) /* Error ... */
|
||||
if (!BIO_write_filename(out, "filename.txt")) /* Error ... */
|
||||
if (out == NULL)
|
||||
/* Error */
|
||||
if (!BIO_write_filename(out, "filename.txt"))
|
||||
/* Error */
|
||||
BIO_printf(out, "Hello World\n");
|
||||
BIO_free(out);
|
||||
|
||||
|
|
|
@ -122,7 +122,8 @@ or
|
|||
|
||||
is called before the read and
|
||||
|
||||
callback_ex(b, BIO_CB_READ | BIO_CB_RETURN, data, dlen, 0, 0L, retvalue, readbytes)
|
||||
callback_ex(b, BIO_CB_READ | BIO_CB_RETURN, data, dlen, 0, 0L, retvalue,
|
||||
readbytes)
|
||||
|
||||
or
|
||||
|
||||
|
@ -140,7 +141,8 @@ or
|
|||
|
||||
is called before the write and
|
||||
|
||||
callback_ex(b, BIO_CB_WRITE | BIO_CB_RETURN, data, dlen, 0, 0L, retvalue, written)
|
||||
callback_ex(b, BIO_CB_WRITE | BIO_CB_RETURN, data, dlen, 0, 0L, retvalue,
|
||||
written)
|
||||
|
||||
or
|
||||
|
||||
|
@ -158,7 +160,8 @@ or
|
|||
|
||||
is called before the operation and
|
||||
|
||||
callback_ex(b, BIO_CB_GETS | BIO_CB_RETURN, buf, size, 0, 0L, retvalue, readbytes)
|
||||
callback_ex(b, BIO_CB_GETS | BIO_CB_RETURN, buf, size, 0, 0L, retvalue,
|
||||
readbytes)
|
||||
|
||||
or
|
||||
|
||||
|
|
|
@ -51,7 +51,8 @@ replace use of BN_CTX_init with BN_CTX_new instead:
|
|||
|
||||
BN_CTX *ctx;
|
||||
ctx = BN_CTX_new();
|
||||
if(!ctx) /* Handle error */
|
||||
if (!ctx)
|
||||
/* error */
|
||||
...
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
|
|
|
@ -169,7 +169,8 @@ Instead applications should create a BN_GENCB structure using BN_GENCB_new:
|
|||
|
||||
BN_GENCB *callback;
|
||||
callback = BN_GENCB_new();
|
||||
if(!callback) /* handle error */
|
||||
if (!callback)
|
||||
/* error */
|
||||
...
|
||||
BN_GENCB_free(callback);
|
||||
|
||||
|
|
|
@ -65,9 +65,9 @@ Load a configuration file and print out any errors and exit (missing file
|
|||
considered fatal):
|
||||
|
||||
if (CONF_modules_load_file(NULL, NULL, 0) <= 0) {
|
||||
fprintf(stderr, "FATAL: error loading configuration file\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(1);
|
||||
fprintf(stderr, "FATAL: error loading configuration file\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Load default configuration file using the section indicated by "myapp",
|
||||
|
@ -75,9 +75,9 @@ tolerate missing files, but exit on other errors:
|
|||
|
||||
if (CONF_modules_load_file(NULL, "myapp",
|
||||
CONF_MFLAGS_IGNORE_MISSING_FILE) <= 0) {
|
||||
fprintf(stderr, "FATAL: error loading configuration file\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(1);
|
||||
fprintf(stderr, "FATAL: error loading configuration file\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Load custom configuration file and section, only print warnings on error,
|
||||
|
@ -85,8 +85,8 @@ missing configuration file ignored:
|
|||
|
||||
if (CONF_modules_load_file("/something/app.cnf", "myapp",
|
||||
CONF_MFLAGS_IGNORE_MISSING_FILE) <= 0) {
|
||||
fprintf(stderr, "WARNING: error loading configuration file\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
fprintf(stderr, "WARNING: error loading configuration file\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
}
|
||||
|
||||
Load and parse configuration file manually, custom error handling:
|
||||
|
@ -96,22 +96,22 @@ Load and parse configuration file manually, custom error handling:
|
|||
long eline;
|
||||
fp = fopen("/somepath/app.cnf", "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Error opening configuration file\n");
|
||||
/* Other missing configuration file behaviour */
|
||||
fprintf(stderr, "Error opening configuration file\n");
|
||||
/* Other missing configuration file behaviour */
|
||||
} else {
|
||||
cnf = NCONF_new(NULL);
|
||||
if (NCONF_load_fp(cnf, fp, &eline) == 0) {
|
||||
fprintf(stderr, "Error on line %ld of configuration file\n", eline);
|
||||
ERR_print_errors_fp(stderr);
|
||||
/* Other malformed configuration file behaviour */
|
||||
} else if (CONF_modules_load(cnf, "appname", 0) <= 0) {
|
||||
fprintf(stderr, "Error configuring application\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
/* Other configuration error behaviour */
|
||||
}
|
||||
fclose(fp);
|
||||
NCONF_free(cnf);
|
||||
}
|
||||
cnf = NCONF_new(NULL);
|
||||
if (NCONF_load_fp(cnf, fp, &eline) == 0) {
|
||||
fprintf(stderr, "Error on line %ld of configuration file\n", eline);
|
||||
ERR_print_errors_fp(stderr);
|
||||
/* Other malformed configuration file behaviour */
|
||||
} else if (CONF_modules_load(cnf, "appname", 0) <= 0) {
|
||||
fprintf(stderr, "Error configuring application\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
/* Other configuration error behaviour */
|
||||
}
|
||||
fclose(fp);
|
||||
NCONF_free(cnf);
|
||||
}
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
|
|
|
@ -100,42 +100,42 @@ crypto.h where use of CRYPTO_THREAD_* types and functions is required.
|
|||
|
||||
This example safely initializes and uses a lock.
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#endif
|
||||
#include <openssl/crypto.h>
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#endif
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
static CRYPTO_ONCE once = CRYPTO_ONCE_STATIC_INIT;
|
||||
static CRYPTO_RWLOCK *lock;
|
||||
static CRYPTO_ONCE once = CRYPTO_ONCE_STATIC_INIT;
|
||||
static CRYPTO_RWLOCK *lock;
|
||||
|
||||
static void myinit(void)
|
||||
{
|
||||
lock = CRYPTO_THREAD_lock_new();
|
||||
}
|
||||
static void myinit(void)
|
||||
{
|
||||
lock = CRYPTO_THREAD_lock_new();
|
||||
}
|
||||
|
||||
static int mylock(void)
|
||||
{
|
||||
if (!CRYPTO_THREAD_run_once(&once, void init) || lock == NULL)
|
||||
return 0;
|
||||
return CRYPTO_THREAD_write_lock(lock);
|
||||
}
|
||||
static int mylock(void)
|
||||
{
|
||||
if (!CRYPTO_THREAD_run_once(&once, void init) || lock == NULL)
|
||||
return 0;
|
||||
return CRYPTO_THREAD_write_lock(lock);
|
||||
}
|
||||
|
||||
static int myunlock(void)
|
||||
{
|
||||
return CRYPTO_THREAD_unlock(lock);
|
||||
}
|
||||
static int myunlock(void)
|
||||
{
|
||||
return CRYPTO_THREAD_unlock(lock);
|
||||
}
|
||||
|
||||
int serialized(void)
|
||||
{
|
||||
int ret = 0;
|
||||
int serialized(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (mylock()) {
|
||||
/* Your code here, do not return without releasing the lock! */
|
||||
ret = ... ;
|
||||
}
|
||||
myunlock();
|
||||
return ret;
|
||||
}
|
||||
if (mylock()) {
|
||||
/* Your code here, do not return without releasing the lock! */
|
||||
ret = ... ;
|
||||
}
|
||||
myunlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
Finalization of locks is an advanced topic, not covered in this example.
|
||||
This can only be done at process exit or when a dynamically loaded library is
|
||||
|
@ -149,9 +149,9 @@ You can find out if OpenSSL was configured with thread support:
|
|||
|
||||
#include <openssl/opensslconf.h>
|
||||
#if defined(OPENSSL_THREADS)
|
||||
// thread support enabled
|
||||
// thread support enabled
|
||||
#else
|
||||
// no thread support
|
||||
// no thread support
|
||||
#endif
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
|
|
@ -136,35 +136,31 @@ named curve prime256v1 (aka P-256).
|
|||
First step: create an EC_KEY object (note: this part is B<not> ECDSA
|
||||
specific)
|
||||
|
||||
int ret;
|
||||
int ret;
|
||||
ECDSA_SIG *sig;
|
||||
EC_KEY *eckey;
|
||||
EC_KEY *eckey;
|
||||
eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
if (eckey == NULL) {
|
||||
/* error */
|
||||
}
|
||||
if (EC_KEY_generate_key(eckey) == 0) {
|
||||
/* error */
|
||||
}
|
||||
if (eckey == NULL)
|
||||
/* error */
|
||||
if (EC_KEY_generate_key(eckey) == 0)
|
||||
/* error */
|
||||
|
||||
Second step: compute the ECDSA signature of a SHA-256 hash value
|
||||
using ECDSA_do_sign():
|
||||
|
||||
sig = ECDSA_do_sign(digest, 32, eckey);
|
||||
if (sig == NULL) {
|
||||
/* error */
|
||||
}
|
||||
if (sig == NULL)
|
||||
/* error */
|
||||
|
||||
or using ECDSA_sign():
|
||||
|
||||
unsigned char *buffer, *pp;
|
||||
int buf_len;
|
||||
int buf_len;
|
||||
buf_len = ECDSA_size(eckey);
|
||||
buffer = OPENSSL_malloc(buf_len);
|
||||
buffer = OPENSSL_malloc(buf_len);
|
||||
pp = buffer;
|
||||
if (ECDSA_sign(0, dgst, dgstlen, pp, &buf_len, eckey) == 0) {
|
||||
/* error */
|
||||
}
|
||||
if (ECDSA_sign(0, dgst, dgstlen, pp, &buf_len, eckey) == 0)
|
||||
/* error */
|
||||
|
||||
Third step: verify the created ECDSA signature using ECDSA_do_verify():
|
||||
|
||||
|
@ -176,13 +172,12 @@ or using ECDSA_verify():
|
|||
|
||||
and finally evaluate the return value:
|
||||
|
||||
if (ret == 1) {
|
||||
/* signature ok */
|
||||
} else if (ret == 0) {
|
||||
/* incorrect signature */
|
||||
} else {
|
||||
/* error */
|
||||
}
|
||||
if (ret == 1)
|
||||
/* signature ok */
|
||||
else if (ret == 0)
|
||||
/* incorrect signature */
|
||||
else
|
||||
/* error */
|
||||
|
||||
=head1 CONFORMING TO
|
||||
|
||||
|
|
|
@ -385,17 +385,19 @@ illustrates how to approach this;
|
|||
const char *engine_id = "ACME";
|
||||
ENGINE_load_builtin_engines();
|
||||
e = ENGINE_by_id(engine_id);
|
||||
if(!e)
|
||||
if (!e)
|
||||
/* the engine isn't available */
|
||||
return;
|
||||
if(!ENGINE_init(e)) {
|
||||
if (!ENGINE_init(e)) {
|
||||
/* the engine couldn't initialise, release 'e' */
|
||||
ENGINE_free(e);
|
||||
return;
|
||||
}
|
||||
if(!ENGINE_set_default_RSA(e))
|
||||
/* This should only happen when 'e' can't initialise, but the previous
|
||||
* statement suggests it did. */
|
||||
if (!ENGINE_set_default_RSA(e))
|
||||
/*
|
||||
* This should only happen when 'e' can't initialise, but the previous
|
||||
* statement suggests it did.
|
||||
*/
|
||||
abort();
|
||||
ENGINE_set_default_DSA(e);
|
||||
ENGINE_set_default_ciphers(e);
|
||||
|
@ -474,9 +476,9 @@ boolean success or failure.
|
|||
ENGINE *e = ENGINE_by_id(engine_id);
|
||||
if (!e) return 0;
|
||||
while (pre_num--) {
|
||||
if(!ENGINE_ctrl_cmd_string(e, pre_cmds[0], pre_cmds[1], 0)) {
|
||||
if (!ENGINE_ctrl_cmd_string(e, pre_cmds[0], pre_cmds[1], 0)) {
|
||||
fprintf(stderr, "Failed command (%s - %s:%s)\n", engine_id,
|
||||
pre_cmds[0], pre_cmds[1] ? pre_cmds[1] : "(NULL)");
|
||||
pre_cmds[0], pre_cmds[1] ? pre_cmds[1] : "(NULL)");
|
||||
ENGINE_free(e);
|
||||
return 0;
|
||||
}
|
||||
|
@ -487,13 +489,15 @@ boolean success or failure.
|
|||
ENGINE_free(e);
|
||||
return 0;
|
||||
}
|
||||
/* ENGINE_init() returned a functional reference, so free the structural
|
||||
* reference from ENGINE_by_id(). */
|
||||
/*
|
||||
* ENGINE_init() returned a functional reference, so free the structural
|
||||
* reference from ENGINE_by_id().
|
||||
*/
|
||||
ENGINE_free(e);
|
||||
while(post_num--) {
|
||||
if(!ENGINE_ctrl_cmd_string(e, post_cmds[0], post_cmds[1], 0)) {
|
||||
while (post_num--) {
|
||||
if (!ENGINE_ctrl_cmd_string(e, post_cmds[0], post_cmds[1], 0)) {
|
||||
fprintf(stderr, "Failed command (%s - %s:%s)\n", engine_id,
|
||||
post_cmds[0], post_cmds[1] ? post_cmds[1] : "(NULL)");
|
||||
post_cmds[0], post_cmds[1] ? post_cmds[1] : "(NULL)");
|
||||
ENGINE_finish(e);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@ B<str> is an array of error string data:
|
|||
|
||||
typedef struct ERR_string_data_st
|
||||
{
|
||||
unsigned long error;
|
||||
char *string;
|
||||
unsigned long error;
|
||||
char *string;
|
||||
} ERR_STRING_DATA;
|
||||
|
||||
The error code is generated from the library number and a function and
|
||||
|
|
|
@ -203,37 +203,37 @@ digest name passed on the command line.
|
|||
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
EVP_MD_CTX *mdctx;
|
||||
const EVP_MD *md;
|
||||
char mess1[] = "Test Message\n";
|
||||
char mess2[] = "Hello World\n";
|
||||
unsigned char md_value[EVP_MAX_MD_SIZE];
|
||||
int md_len, i;
|
||||
EVP_MD_CTX *mdctx;
|
||||
const EVP_MD *md;
|
||||
char mess1[] = "Test Message\n";
|
||||
char mess2[] = "Hello World\n";
|
||||
unsigned char md_value[EVP_MAX_MD_SIZE];
|
||||
int md_len, i;
|
||||
|
||||
if (argv[1] == NULL) {
|
||||
printf("Usage: mdtest digestname\n");
|
||||
exit(1);
|
||||
}
|
||||
if (argv[1] == NULL) {
|
||||
printf("Usage: mdtest digestname\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
md = EVP_get_digestbyname(argv[1]);
|
||||
if (md == NULL) {
|
||||
printf("Unknown message digest %s\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
md = EVP_get_digestbyname(argv[1]);
|
||||
if (md == NULL) {
|
||||
printf("Unknown message digest %s\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mdctx = EVP_MD_CTX_new();
|
||||
EVP_DigestInit_ex(mdctx, md, NULL);
|
||||
EVP_DigestUpdate(mdctx, mess1, strlen(mess1));
|
||||
EVP_DigestUpdate(mdctx, mess2, strlen(mess2));
|
||||
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
mdctx = EVP_MD_CTX_new();
|
||||
EVP_DigestInit_ex(mdctx, md, NULL);
|
||||
EVP_DigestUpdate(mdctx, mess1, strlen(mess1));
|
||||
EVP_DigestUpdate(mdctx, mess2, strlen(mess2));
|
||||
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
|
||||
printf("Digest is: ");
|
||||
for (i = 0; i < md_len; i++)
|
||||
printf("%02x", md_value[i]);
|
||||
printf("\n");
|
||||
printf("Digest is: ");
|
||||
for (i = 0; i < md_len; i++)
|
||||
printf("%02x", md_value[i]);
|
||||
printf("\n");
|
||||
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
|
|
@ -540,101 +540,101 @@ for certain common S/MIME ciphers (RC2, DES, triple DES) in CBC mode.
|
|||
Encrypt a string using IDEA:
|
||||
|
||||
int do_crypt(char *outfile)
|
||||
{
|
||||
unsigned char outbuf[1024];
|
||||
int outlen, tmplen;
|
||||
/* Bogus key and IV: we'd normally set these from
|
||||
* another source.
|
||||
*/
|
||||
unsigned char key[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
|
||||
unsigned char iv[] = {1,2,3,4,5,6,7,8};
|
||||
char intext[] = "Some Crypto Text";
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
FILE *out;
|
||||
{
|
||||
unsigned char outbuf[1024];
|
||||
int outlen, tmplen;
|
||||
/*
|
||||
* Bogus key and IV: we'd normally set these from
|
||||
* another source.
|
||||
*/
|
||||
unsigned char key[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
|
||||
unsigned char iv[] = {1,2,3,4,5,6,7,8};
|
||||
char intext[] = "Some Crypto Text";
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
FILE *out;
|
||||
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
EVP_EncryptInit_ex(ctx, EVP_idea_cbc(), NULL, key, iv);
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
EVP_EncryptInit_ex(ctx, EVP_idea_cbc(), NULL, key, iv);
|
||||
|
||||
if(!EVP_EncryptUpdate(ctx, outbuf, &outlen, intext, strlen(intext)))
|
||||
{
|
||||
/* Error */
|
||||
return 0;
|
||||
}
|
||||
/* Buffer passed to EVP_EncryptFinal() must be after data just
|
||||
* encrypted to avoid overwriting it.
|
||||
*/
|
||||
if(!EVP_EncryptFinal_ex(ctx, outbuf + outlen, &tmplen))
|
||||
{
|
||||
/* Error */
|
||||
return 0;
|
||||
}
|
||||
outlen += tmplen;
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
/* Need binary mode for fopen because encrypted data is
|
||||
* binary data. Also cannot use strlen() on it because
|
||||
* it won't be null terminated and may contain embedded
|
||||
* nulls.
|
||||
*/
|
||||
out = fopen(outfile, "wb");
|
||||
fwrite(outbuf, 1, outlen, out);
|
||||
fclose(out);
|
||||
return 1;
|
||||
}
|
||||
if (!EVP_EncryptUpdate(ctx, outbuf, &outlen, intext, strlen(intext))) {
|
||||
/* Error */
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Buffer passed to EVP_EncryptFinal() must be after data just
|
||||
* encrypted to avoid overwriting it.
|
||||
*/
|
||||
if (!EVP_EncryptFinal_ex(ctx, outbuf + outlen, &tmplen)) {
|
||||
/* Error */
|
||||
return 0;
|
||||
}
|
||||
outlen += tmplen;
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
/*
|
||||
* Need binary mode for fopen because encrypted data is
|
||||
* binary data. Also cannot use strlen() on it because
|
||||
* it won't be NUL terminated and may contain embedded
|
||||
* NULs.
|
||||
*/
|
||||
out = fopen(outfile, "wb");
|
||||
fwrite(outbuf, 1, outlen, out);
|
||||
fclose(out);
|
||||
return 1;
|
||||
}
|
||||
|
||||
The ciphertext from the above example can be decrypted using the B<openssl>
|
||||
utility with the command line (shown on two lines for clarity):
|
||||
|
||||
openssl idea -d <filename
|
||||
-K 000102030405060708090A0B0C0D0E0F -iv 0102030405060708
|
||||
openssl idea -d \
|
||||
-K 000102030405060708090A0B0C0D0E0F -iv 0102030405060708 <filename
|
||||
|
||||
General encryption and decryption function example using FILE I/O and AES128
|
||||
with a 128-bit key:
|
||||
|
||||
int do_crypt(FILE *in, FILE *out, int do_encrypt)
|
||||
{
|
||||
/* Allow enough space in output buffer for additional block */
|
||||
unsigned char inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
|
||||
int inlen, outlen;
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
/* Bogus key and IV: we'd normally set these from
|
||||
* another source.
|
||||
*/
|
||||
unsigned char key[] = "0123456789abcdeF";
|
||||
unsigned char iv[] = "1234567887654321";
|
||||
{
|
||||
/* Allow enough space in output buffer for additional block */
|
||||
unsigned char inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
|
||||
int inlen, outlen;
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
/*
|
||||
* Bogus key and IV: we'd normally set these from
|
||||
* another source.
|
||||
*/
|
||||
unsigned char key[] = "0123456789abcdeF";
|
||||
unsigned char iv[] = "1234567887654321";
|
||||
|
||||
/* Don't set key or IV right away; we want to check lengths */
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
EVP_CipherInit_ex(&ctx, EVP_aes_128_cbc(), NULL, NULL, NULL,
|
||||
do_encrypt);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
|
||||
/* Don't set key or IV right away; we want to check lengths */
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
EVP_CipherInit_ex(&ctx, EVP_aes_128_cbc(), NULL, NULL, NULL,
|
||||
do_encrypt);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
|
||||
|
||||
/* Now we can set key and IV */
|
||||
EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, do_encrypt);
|
||||
/* Now we can set key and IV */
|
||||
EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, do_encrypt);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
inlen = fread(inbuf, 1, 1024, in);
|
||||
if (inlen <= 0) break;
|
||||
if(!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen))
|
||||
{
|
||||
/* Error */
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
fwrite(outbuf, 1, outlen, out);
|
||||
}
|
||||
if(!EVP_CipherFinal_ex(ctx, outbuf, &outlen))
|
||||
{
|
||||
/* Error */
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
fwrite(outbuf, 1, outlen, out);
|
||||
for (;;) {
|
||||
inlen = fread(inbuf, 1, 1024, in);
|
||||
if (inlen <= 0)
|
||||
break;
|
||||
if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
|
||||
/* Error */
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
fwrite(outbuf, 1, outlen, out);
|
||||
}
|
||||
if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen)) {
|
||||
/* Error */
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
fwrite(outbuf, 1, outlen, out);
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return 1;
|
||||
}
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
|
|
@ -132,17 +132,17 @@ salt value "salt" and info value "label":
|
|||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
||||
|
||||
if (EVP_PKEY_derive_init(pctx) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, "salt", 4) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set1_hkdf_key(pctx, "secret", 6) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_add1_hkdf_info(pctx, "label", 6) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_derive(pctx, out, &outlen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
=head1 CONFORMING TO
|
||||
|
||||
|
|
|
@ -80,15 +80,15 @@ and seed value "seed":
|
|||
size_t outlen = sizeof(out);
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL);
|
||||
if (EVP_PKEY_derive_init(pctx) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_tls1_prf_md(pctx, EVP_sha256()) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, "secret", 6) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, "seed", 4) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_derive(pctx, out, &outlen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
|
|
@ -52,28 +52,29 @@ Decrypt data using OAEP (for RSA keys):
|
|||
unsigned char *out, *in;
|
||||
size_t outlen, inlen;
|
||||
EVP_PKEY *key;
|
||||
/* NB: assumes key in, inlen are already set up
|
||||
/*
|
||||
* NB: assumes key in, inlen are already set up
|
||||
* and that key is an RSA private key
|
||||
*/
|
||||
ctx = EVP_PKEY_CTX_new(key);
|
||||
if (!ctx)
|
||||
/* Error occurred */
|
||||
/* Error occurred */
|
||||
if (EVP_PKEY_decrypt_init(ctx) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_OAEP_PADDING) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Determine buffer length */
|
||||
if (EVP_PKEY_decrypt(ctx, NULL, &outlen, in, inlen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
out = OPENSSL_malloc(outlen);
|
||||
|
||||
if (!out)
|
||||
/* malloc failure */
|
||||
/* malloc failure */
|
||||
|
||||
if (EVP_PKEY_decrypt(ctx, out, &outlen, in, inlen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Decrypted data is outlen bytes written to buffer out */
|
||||
|
||||
|
|
|
@ -57,23 +57,23 @@ Derive shared secret (for example DH or EC keys):
|
|||
|
||||
ctx = EVP_PKEY_CTX_new(pkey);
|
||||
if (!ctx)
|
||||
/* Error occurred */
|
||||
/* Error occurred */
|
||||
if (EVP_PKEY_derive_init(ctx) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_derive_set_peer(ctx, peerkey) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Determine buffer length */
|
||||
if (EVP_PKEY_derive(ctx, NULL, &skeylen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
skey = OPENSSL_malloc(skeylen);
|
||||
|
||||
if (!skey)
|
||||
/* malloc failure */
|
||||
/* malloc failure */
|
||||
|
||||
if (EVP_PKEY_derive(ctx, skey, &skeylen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Shared secret is skey bytes written to buffer skey */
|
||||
|
||||
|
|
|
@ -56,28 +56,29 @@ set 'eng = NULL;' to start with the default OpenSSL RSA implementation:
|
|||
unsigned char *out, *in;
|
||||
size_t outlen, inlen;
|
||||
EVP_PKEY *key;
|
||||
/* NB: assumes eng, key, in, inlen are already set up,
|
||||
/*
|
||||
* NB: assumes eng, key, in, inlen are already set up,
|
||||
* and that key is an RSA public key
|
||||
*/
|
||||
ctx = EVP_PKEY_CTX_new(key, eng);
|
||||
if (!ctx)
|
||||
/* Error occurred */
|
||||
/* Error occurred */
|
||||
if (EVP_PKEY_encrypt_init(ctx) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_OAEP_PADDING) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Determine buffer length */
|
||||
if (EVP_PKEY_encrypt(ctx, NULL, &outlen, in, inlen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
out = OPENSSL_malloc(outlen);
|
||||
|
||||
if (!out)
|
||||
/* malloc failure */
|
||||
/* malloc failure */
|
||||
|
||||
if (EVP_PKEY_encrypt(ctx, out, &outlen, in, inlen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Encrypted data is outlen bytes written to buffer out */
|
||||
|
||||
|
|
|
@ -100,15 +100,15 @@ Generate a 2048 bit RSA key:
|
|||
EVP_PKEY *pkey = NULL;
|
||||
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
|
||||
if (!ctx)
|
||||
/* Error occurred */
|
||||
/* Error occurred */
|
||||
if (EVP_PKEY_keygen_init(ctx) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Generate key */
|
||||
if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
Generate a key from a set of parameters:
|
||||
|
||||
|
@ -120,13 +120,13 @@ Generate a key from a set of parameters:
|
|||
/* Assumed param is set up already */
|
||||
ctx = EVP_PKEY_CTX_new(param);
|
||||
if (!ctx)
|
||||
/* Error occurred */
|
||||
/* Error occurred */
|
||||
if (EVP_PKEY_keygen_init(ctx) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Generate key */
|
||||
if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
Example of generation callback for OpenSSL public key implementations:
|
||||
|
||||
|
@ -135,19 +135,22 @@ Example of generation callback for OpenSSL public key implementations:
|
|||
EVP_PKEY_CTX_set_app_data(ctx, status_bio);
|
||||
|
||||
static int genpkey_cb(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
char c = '*';
|
||||
BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
|
||||
int p;
|
||||
p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
|
||||
if (p == 0) c = '.';
|
||||
if (p == 1) c = '+';
|
||||
if (p == 2) c = '*';
|
||||
if (p == 3) c = '\n';
|
||||
BIO_write(b, &c, 1);
|
||||
(void)BIO_flush(b);
|
||||
return 1;
|
||||
}
|
||||
{
|
||||
char c = '*';
|
||||
BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
|
||||
int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
|
||||
if (p == 0)
|
||||
c = '.';
|
||||
if (p == 1)
|
||||
c = '+';
|
||||
if (p == 2)
|
||||
c = '*';
|
||||
if (p == 3)
|
||||
c = '\n';
|
||||
BIO_write(b, &c, 1);
|
||||
(void)BIO_flush(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
|
|
@ -66,25 +66,25 @@ Sign data using RSA with PKCS#1 padding and SHA256 digest:
|
|||
*/
|
||||
ctx = EVP_PKEY_CTX_new(signing_key, NULL /* no engine */);
|
||||
if (!ctx)
|
||||
/* Error occurred */
|
||||
/* Error occurred */
|
||||
if (EVP_PKEY_sign_init(ctx) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Determine buffer length */
|
||||
if (EVP_PKEY_sign(ctx, NULL, &siglen, md, mdlen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
sig = OPENSSL_malloc(siglen);
|
||||
|
||||
if (!sig)
|
||||
/* malloc failure */
|
||||
/* malloc failure */
|
||||
|
||||
if (EVP_PKEY_sign(ctx, sig, &siglen, md, mdlen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Signature is siglen bytes written to buffer sig */
|
||||
|
||||
|
|
|
@ -55,23 +55,25 @@ Verify signature using PKCS#1 and SHA256 digest:
|
|||
unsigned char *md, *sig;
|
||||
size_t mdlen, siglen;
|
||||
EVP_PKEY *verify_key;
|
||||
/* NB: assumes verify_key, sig, siglen md and mdlen are already set up
|
||||
/*
|
||||
* NB: assumes verify_key, sig, siglen md and mdlen are already set up
|
||||
* and that verify_key is an RSA public key
|
||||
*/
|
||||
ctx = EVP_PKEY_CTX_new(verify_key);
|
||||
if (!ctx)
|
||||
/* Error occurred */
|
||||
/* Error occurred */
|
||||
if (EVP_PKEY_verify_init(ctx) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Perform operation */
|
||||
ret = EVP_PKEY_verify(ctx, sig, siglen, md, mdlen);
|
||||
|
||||
/* ret == 1 indicates success, 0 verify failure and < 0 for some
|
||||
/*
|
||||
* ret == 1 indicates success, 0 verify failure and < 0 for some
|
||||
* other error.
|
||||
*/
|
||||
|
||||
|
|
|
@ -60,30 +60,31 @@ Recover digest originally signed using PKCS#1 and SHA256 digest:
|
|||
unsigned char *rout, *sig;
|
||||
size_t routlen, siglen;
|
||||
EVP_PKEY *verify_key;
|
||||
/* NB: assumes verify_key, sig and siglen are already set up
|
||||
/*
|
||||
* NB: assumes verify_key, sig and siglen are already set up
|
||||
* and that verify_key is an RSA public key
|
||||
*/
|
||||
ctx = EVP_PKEY_CTX_new(verify_key);
|
||||
if (!ctx)
|
||||
/* Error occurred */
|
||||
/* Error occurred */
|
||||
if (EVP_PKEY_verify_recover_init(ctx) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Determine buffer length */
|
||||
if (EVP_PKEY_verify_recover(ctx, NULL, &routlen, sig, siglen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
rout = OPENSSL_malloc(routlen);
|
||||
|
||||
if (!rout)
|
||||
/* malloc failure */
|
||||
/* malloc failure */
|
||||
|
||||
if (EVP_PKEY_verify_recover(ctx, rout, &routlen, sig, siglen) <= 0)
|
||||
/* Error */
|
||||
/* Error */
|
||||
|
||||
/* Recovered data is routlen bytes written to buffer rout */
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ Create an object for B<commonName>:
|
|||
Check if an object is B<commonName>
|
||||
|
||||
if (OBJ_obj2nid(obj) == NID_commonName)
|
||||
/* Do something */
|
||||
/* Do something */
|
||||
|
||||
Create a new NID and initialize an object from it:
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ B<issuer>:
|
|||
if (OCSP_REQUEST_add0_id(req, cid) == NULL)
|
||||
/* error */
|
||||
|
||||
/* Do something with req, e.g. query responder */
|
||||
/* Do something with req, e.g. query responder */
|
||||
|
||||
OCSP_REQUEST_free(req);
|
||||
|
||||
|
|
|
@ -306,43 +306,38 @@ Read a certificate in PEM format from a BIO:
|
|||
|
||||
X509 *x;
|
||||
x = PEM_read_bio_X509(bp, NULL, 0, NULL);
|
||||
if (x == NULL) {
|
||||
if (x == NULL)
|
||||
/* Error */
|
||||
}
|
||||
|
||||
Alternative method:
|
||||
|
||||
X509 *x = NULL;
|
||||
if (!PEM_read_bio_X509(bp, &x, 0, NULL)) {
|
||||
if (!PEM_read_bio_X509(bp, &x, 0, NULL))
|
||||
/* Error */
|
||||
}
|
||||
|
||||
Write a certificate to a BIO:
|
||||
|
||||
if (!PEM_write_bio_X509(bp, x)) {
|
||||
if (!PEM_write_bio_X509(bp, x))
|
||||
/* Error */
|
||||
}
|
||||
|
||||
Write a private key (using traditional format) to a BIO using
|
||||
triple DES encryption, the pass phrase is prompted for:
|
||||
|
||||
if (!PEM_write_bio_PrivateKey(bp, key, EVP_des_ede3_cbc(), NULL, 0, 0, NULL)) {
|
||||
if (!PEM_write_bio_PrivateKey(bp, key, EVP_des_ede3_cbc(), NULL, 0, 0, NULL))
|
||||
/* Error */
|
||||
}
|
||||
|
||||
Write a private key (using PKCS#8 format) to a BIO using triple
|
||||
DES encryption, using the pass phrase "hello":
|
||||
|
||||
if (!PEM_write_bio_PKCS8PrivateKey(bp, key, EVP_des_ede3_cbc(), NULL, 0, 0, "hello")) {
|
||||
if (!PEM_write_bio_PKCS8PrivateKey(bp, key, EVP_des_ede3_cbc(),
|
||||
NULL, 0, 0, "hello"))
|
||||
/* Error */
|
||||
}
|
||||
|
||||
Read a private key from a BIO using a pass phrase callback:
|
||||
|
||||
key = PEM_read_bio_PrivateKey(bp, NULL, pass_cb, "My Private Key");
|
||||
if (key == NULL) {
|
||||
if (key == NULL)
|
||||
/* Error */
|
||||
}
|
||||
|
||||
Skeleton pass phrase callback:
|
||||
|
||||
|
@ -432,9 +427,8 @@ The pseudo code to derive the key would look similar to:
|
|||
|
||||
memcpy(iv, HexToBin("3F17F5316E2BAC89"), niv);
|
||||
rc = EVP_BytesToKey(cipher, md, iv /*salt*/, pword, plen, 1, key, NULL /*iv*/);
|
||||
if (rc != nkey) {
|
||||
if (rc != nkey)
|
||||
/* Error */
|
||||
}
|
||||
|
||||
/* On success, use key and iv to initialize the cipher */
|
||||
|
||||
|
|
|
@ -47,38 +47,38 @@ the result to a new file.
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
PKCS12 *p12;
|
||||
if (argc != 5) {
|
||||
fprintf(stderr, "Usage: pkread p12file password newpass opfile\n");
|
||||
return 1;
|
||||
}
|
||||
if ((fp = fopen(argv[1], "rb")) == NULL) {
|
||||
fprintf(stderr, "Error opening file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
p12 = d2i_PKCS12_fp(fp, NULL);
|
||||
fclose(fp);
|
||||
if (p12 == NULL) {
|
||||
fprintf(stderr, "Error reading PKCS#12 file\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
return 1;
|
||||
}
|
||||
if (PKCS12_newpass(p12, argv[2], argv[3]) == 0) {
|
||||
fprintf(stderr, "Error changing password\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
PKCS12_free(p12);
|
||||
return 1;
|
||||
}
|
||||
if ((fp = fopen(argv[4], "wb")) == NULL) {
|
||||
fprintf(stderr, "Error opening file %s\n", argv[4]);
|
||||
PKCS12_free(p12);
|
||||
return 1;
|
||||
}
|
||||
i2d_PKCS12_fp(fp, p12);
|
||||
PKCS12_free(p12);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
FILE *fp;
|
||||
PKCS12 *p12;
|
||||
if (argc != 5) {
|
||||
fprintf(stderr, "Usage: pkread p12file password newpass opfile\n");
|
||||
return 1;
|
||||
}
|
||||
if ((fp = fopen(argv[1], "rb")) == NULL) {
|
||||
fprintf(stderr, "Error opening file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
p12 = d2i_PKCS12_fp(fp, NULL);
|
||||
fclose(fp);
|
||||
if (p12 == NULL) {
|
||||
fprintf(stderr, "Error reading PKCS#12 file\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
return 1;
|
||||
}
|
||||
if (PKCS12_newpass(p12, argv[2], argv[3]) == 0) {
|
||||
fprintf(stderr, "Error changing password\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
PKCS12_free(p12);
|
||||
return 1;
|
||||
}
|
||||
if ((fp = fopen(argv[4], "wb")) == NULL) {
|
||||
fprintf(stderr, "Error opening file %s\n", argv[4]);
|
||||
PKCS12_free(p12);
|
||||
return 1;
|
||||
}
|
||||
i2d_PKCS12_fp(fp, p12);
|
||||
PKCS12_free(p12);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -37,12 +37,12 @@ API is being used, so this function is no longer recommended.
|
|||
|
||||
typedef struct rand_meth_st
|
||||
{
|
||||
void (*seed)(const void *buf, int num);
|
||||
int (*bytes)(unsigned char *buf, int num);
|
||||
void (*cleanup)(void);
|
||||
void (*add)(const void *buf, int num, int entropy);
|
||||
int (*pseudorand)(unsigned char *buf, int num);
|
||||
int (*status)(void);
|
||||
void (*seed)(const void *buf, int num);
|
||||
int (*bytes)(unsigned char *buf, int num);
|
||||
void (*cleanup)(void);
|
||||
void (*add)(const void *buf, int num, int entropy);
|
||||
int (*pseudorand)(unsigned char *buf, int num);
|
||||
int (*status)(void);
|
||||
} RAND_METHOD;
|
||||
|
||||
The components point to method implementations used by (or called by), in order,
|
||||
|
|
|
@ -81,56 +81,56 @@ the default method is used.
|
|||
typedef struct rsa_meth_st
|
||||
{
|
||||
/* name of the implementation */
|
||||
const char *name;
|
||||
const char *name;
|
||||
|
||||
/* encrypt */
|
||||
int (*rsa_pub_enc)(int flen, unsigned char *from,
|
||||
unsigned char *to, RSA *rsa, int padding);
|
||||
int (*rsa_pub_enc)(int flen, unsigned char *from,
|
||||
unsigned char *to, RSA *rsa, int padding);
|
||||
|
||||
/* verify arbitrary data */
|
||||
int (*rsa_pub_dec)(int flen, unsigned char *from,
|
||||
unsigned char *to, RSA *rsa, int padding);
|
||||
int (*rsa_pub_dec)(int flen, unsigned char *from,
|
||||
unsigned char *to, RSA *rsa, int padding);
|
||||
|
||||
/* sign arbitrary data */
|
||||
int (*rsa_priv_enc)(int flen, unsigned char *from,
|
||||
unsigned char *to, RSA *rsa, int padding);
|
||||
int (*rsa_priv_enc)(int flen, unsigned char *from,
|
||||
unsigned char *to, RSA *rsa, int padding);
|
||||
|
||||
/* decrypt */
|
||||
int (*rsa_priv_dec)(int flen, unsigned char *from,
|
||||
unsigned char *to, RSA *rsa, int padding);
|
||||
int (*rsa_priv_dec)(int flen, unsigned char *from,
|
||||
unsigned char *to, RSA *rsa, int padding);
|
||||
|
||||
/* compute r0 = r0 ^ I mod rsa->n (May be NULL for some
|
||||
implementations) */
|
||||
int (*rsa_mod_exp)(BIGNUM *r0, BIGNUM *I, RSA *rsa);
|
||||
/* compute r0 = r0 ^ I mod rsa->n (May be NULL for some implementations) */
|
||||
int (*rsa_mod_exp)(BIGNUM *r0, BIGNUM *I, RSA *rsa);
|
||||
|
||||
/* compute r = a ^ p mod m (May be NULL for some implementations) */
|
||||
int (*bn_mod_exp)(BIGNUM *r, BIGNUM *a, const BIGNUM *p,
|
||||
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
|
||||
int (*bn_mod_exp)(BIGNUM *r, BIGNUM *a, const BIGNUM *p,
|
||||
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
|
||||
|
||||
/* called at RSA_new */
|
||||
int (*init)(RSA *rsa);
|
||||
int (*init)(RSA *rsa);
|
||||
|
||||
/* called at RSA_free */
|
||||
int (*finish)(RSA *rsa);
|
||||
int (*finish)(RSA *rsa);
|
||||
|
||||
/* RSA_FLAG_EXT_PKEY - rsa_mod_exp is called for private key
|
||||
/*
|
||||
* RSA_FLAG_EXT_PKEY - rsa_mod_exp is called for private key
|
||||
* operations, even if p,q,dmp1,dmq1,iqmp
|
||||
* are NULL
|
||||
* RSA_METHOD_FLAG_NO_CHECK - don't check pub/private match
|
||||
*/
|
||||
int flags;
|
||||
int flags;
|
||||
|
||||
char *app_data; /* ?? */
|
||||
char *app_data; /* ?? */
|
||||
|
||||
int (*rsa_sign)(int type,
|
||||
const unsigned char *m, unsigned int m_length,
|
||||
unsigned char *sigret, unsigned int *siglen, const RSA *rsa);
|
||||
int (*rsa_verify)(int dtype,
|
||||
const unsigned char *m, unsigned int m_length,
|
||||
const unsigned char *sigbuf, unsigned int siglen,
|
||||
const RSA *rsa);
|
||||
int (*rsa_sign)(int type,
|
||||
const unsigned char *m, unsigned int m_length,
|
||||
unsigned char *sigret, unsigned int *siglen, const RSA *rsa);
|
||||
int (*rsa_verify)(int dtype,
|
||||
const unsigned char *m, unsigned int m_length,
|
||||
const unsigned char *sigbuf, unsigned int siglen,
|
||||
const RSA *rsa);
|
||||
/* keygen. If NULL builtin RSA key generation will be used */
|
||||
int (*rsa_keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
|
||||
int (*rsa_keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
|
||||
|
||||
} RSA_METHOD;
|
||||
|
||||
|
|
|
@ -18,21 +18,21 @@ SCT_get_source, SCT_set_source
|
|||
#include <openssl/ct.h>
|
||||
|
||||
typedef enum {
|
||||
CT_LOG_ENTRY_TYPE_NOT_SET = -1,
|
||||
CT_LOG_ENTRY_TYPE_X509 = 0,
|
||||
CT_LOG_ENTRY_TYPE_PRECERT = 1
|
||||
CT_LOG_ENTRY_TYPE_NOT_SET = -1,
|
||||
CT_LOG_ENTRY_TYPE_X509 = 0,
|
||||
CT_LOG_ENTRY_TYPE_PRECERT = 1
|
||||
} ct_log_entry_type_t;
|
||||
|
||||
typedef enum {
|
||||
SCT_VERSION_NOT_SET = -1,
|
||||
SCT_VERSION_V1 = 0
|
||||
SCT_VERSION_NOT_SET = -1,
|
||||
SCT_VERSION_V1 = 0
|
||||
} sct_version_t;
|
||||
|
||||
typedef enum {
|
||||
SCT_SOURCE_UNKNOWN,
|
||||
SCT_SOURCE_TLS_EXTENSION,
|
||||
SCT_SOURCE_X509V3_EXTENSION,
|
||||
SCT_SOURCE_OCSP_STAPLED_RESPONSE
|
||||
SCT_SOURCE_UNKNOWN,
|
||||
SCT_SOURCE_TLS_EXTENSION,
|
||||
SCT_SOURCE_X509V3_EXTENSION,
|
||||
SCT_SOURCE_OCSP_STAPLED_RESPONSE
|
||||
} sct_source_t;
|
||||
|
||||
SCT *SCT_new(void);
|
||||
|
|
|
@ -10,12 +10,12 @@ checks Signed Certificate Timestamps (SCTs) are valid
|
|||
#include <openssl/ct.h>
|
||||
|
||||
typedef enum {
|
||||
SCT_VALIDATION_STATUS_NOT_SET,
|
||||
SCT_VALIDATION_STATUS_UNKNOWN_LOG,
|
||||
SCT_VALIDATION_STATUS_VALID,
|
||||
SCT_VALIDATION_STATUS_INVALID,
|
||||
SCT_VALIDATION_STATUS_UNVERIFIED,
|
||||
SCT_VALIDATION_STATUS_UNKNOWN_VERSION
|
||||
SCT_VALIDATION_STATUS_NOT_SET,
|
||||
SCT_VALIDATION_STATUS_UNKNOWN_LOG,
|
||||
SCT_VALIDATION_STATUS_VALID,
|
||||
SCT_VALIDATION_STATUS_INVALID,
|
||||
SCT_VALIDATION_STATUS_UNVERIFIED,
|
||||
SCT_VALIDATION_STATUS_UNKNOWN_VERSION
|
||||
} sct_validation_status_t;
|
||||
|
||||
int SCT_validate(SCT *sct, const CT_POLICY_EVAL_CTX *ctx);
|
||||
|
|
|
@ -41,15 +41,12 @@ If the file "config.cnf" contains the following:
|
|||
|
||||
[test_sect]
|
||||
# list of confuration modules
|
||||
|
||||
ssl_conf = ssl_sect
|
||||
|
||||
[ssl_sect]
|
||||
|
||||
server = server_section
|
||||
|
||||
[server_section]
|
||||
|
||||
RSA.Certificate = server-rsa.pem
|
||||
ECDSA.Certificate = server-ecdsa.pem
|
||||
Ciphers = ALL:!RC4
|
||||
|
@ -57,8 +54,8 @@ If the file "config.cnf" contains the following:
|
|||
An application could call:
|
||||
|
||||
if (CONF_modules_load_file("config.cnf", "testapp", 0) <= 0) {
|
||||
fprintf(stderr, "Error processing config file\n");
|
||||
goto err;
|
||||
fprintf(stderr, "Error processing config file\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ctx = SSL_CTX_new(TLS_server_method());
|
||||
|
|
|
@ -190,139 +190,137 @@ The actual name matched in the certificate (which might be a wildcard) is
|
|||
retrieved, and must be copied by the application if it is to be retained beyond
|
||||
the lifetime of the SSL connection.
|
||||
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
int (*verify_cb)(int ok, X509_STORE_CTX *sctx) = NULL;
|
||||
int num_usable = 0;
|
||||
const char *nexthop_domain = "example.com";
|
||||
const char *dane_tlsa_domain = "smtp.example.com";
|
||||
uint8_t usage, selector, mtype;
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
int (*verify_cb)(int ok, X509_STORE_CTX *sctx) = NULL;
|
||||
int num_usable = 0;
|
||||
const char *nexthop_domain = "example.com";
|
||||
const char *dane_tlsa_domain = "smtp.example.com";
|
||||
uint8_t usage, selector, mtype;
|
||||
|
||||
if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL)
|
||||
/* handle error */
|
||||
if (SSL_CTX_dane_enable(ctx) <= 0)
|
||||
/* handle error */
|
||||
if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL)
|
||||
/* error */
|
||||
if (SSL_CTX_dane_enable(ctx) <= 0)
|
||||
/* error */
|
||||
if ((ssl = SSL_new(ctx)) == NULL)
|
||||
/* error */
|
||||
if (SSL_dane_enable(ssl, dane_tlsa_domain) <= 0)
|
||||
/* error */
|
||||
|
||||
if ((ssl = SSL_new(ctx)) == NULL)
|
||||
/* handle error */
|
||||
/*
|
||||
* For many applications it is safe to skip DANE-EE(3) namechecks. Do not
|
||||
* disable the checks unless "unknown key share" attacks pose no risk for
|
||||
* your application.
|
||||
*/
|
||||
SSL_dane_set_flags(ssl, DANE_FLAG_NO_DANE_EE_NAMECHECKS);
|
||||
|
||||
if (SSL_dane_enable(ssl, dane_tlsa_domain) <= 0)
|
||||
/* handle error */
|
||||
if (!SSL_add1_host(ssl, nexthop_domain))
|
||||
/* error */
|
||||
SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
|
||||
/*
|
||||
* For many applications it is safe to skip DANE-EE(3) namechecks. Do not
|
||||
* disable the checks unless "unknown key share" attacks pose no risk for
|
||||
* your application.
|
||||
*/
|
||||
SSL_dane_set_flags(ssl, DANE_FLAG_NO_DANE_EE_NAMECHECKS);
|
||||
for (... each TLSA record ...) {
|
||||
unsigned char *data;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
if (!SSL_add1_host(ssl, nexthop_domain))
|
||||
/* handle error */
|
||||
SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
/* set usage, selector, mtype, data, len */
|
||||
|
||||
for (... each TLSA record ...) {
|
||||
unsigned char *data;
|
||||
size_t len;
|
||||
int ret;
|
||||
/*
|
||||
* Opportunistic DANE TLS clients support only DANE-TA(2) or DANE-EE(3).
|
||||
* They treat all other certificate usages, and in particular PKIX-TA(0)
|
||||
* and PKIX-EE(1), as unusable.
|
||||
*/
|
||||
switch (usage) {
|
||||
default:
|
||||
case 0: /* PKIX-TA(0) */
|
||||
case 1: /* PKIX-EE(1) */
|
||||
continue;
|
||||
case 2: /* DANE-TA(2) */
|
||||
case 3: /* DANE-EE(3) */
|
||||
break;
|
||||
}
|
||||
|
||||
/* set usage, selector, mtype, data, len */
|
||||
ret = SSL_dane_tlsa_add(ssl, usage, selector, mtype, data, len);
|
||||
/* free data as appropriate */
|
||||
|
||||
/*
|
||||
* Opportunistic DANE TLS clients support only DANE-TA(2) or DANE-EE(3).
|
||||
* They treat all other certificate usages, and in particular PKIX-TA(0)
|
||||
* and PKIX-EE(1), as unusable.
|
||||
*/
|
||||
switch (usage) {
|
||||
default:
|
||||
case 0: /* PKIX-TA(0) */
|
||||
case 1: /* PKIX-EE(1) */
|
||||
continue;
|
||||
case 2: /* DANE-TA(2) */
|
||||
case 3: /* DANE-EE(3) */
|
||||
break;
|
||||
}
|
||||
if (ret < 0)
|
||||
/* handle SSL library internal error */
|
||||
else if (ret == 0)
|
||||
/* handle unusable TLSA record */
|
||||
else
|
||||
++num_usable;
|
||||
}
|
||||
|
||||
ret = SSL_dane_tlsa_add(ssl, usage, selector, mtype, data, len);
|
||||
/* free data as appropriate */
|
||||
/*
|
||||
* At this point, the verification mode is still the default SSL_VERIFY_NONE.
|
||||
* Opportunistic DANE clients use unauthenticated TLS when all TLSA records
|
||||
* are unusable, so continue the handshake even if authentication fails.
|
||||
*/
|
||||
if (num_usable == 0) {
|
||||
/* Log all records unusable? */
|
||||
|
||||
if (ret < 0)
|
||||
/* handle SSL library internal error */
|
||||
else if (ret == 0)
|
||||
/* handle unusable TLSA record */
|
||||
else
|
||||
++num_usable;
|
||||
}
|
||||
/* Optionally set verify_cb to a suitable non-NULL callback. */
|
||||
SSL_set_verify(ssl, SSL_VERIFY_NONE, verify_cb);
|
||||
} else {
|
||||
/* At least one usable record. We expect to verify the peer */
|
||||
|
||||
/*
|
||||
* At this point, the verification mode is still the default SSL_VERIFY_NONE.
|
||||
* Opportunistic DANE clients use unauthenticated TLS when all TLSA records
|
||||
* are unusable, so continue the handshake even if authentication fails.
|
||||
*/
|
||||
if (num_usable == 0) {
|
||||
/* Log all records unusable? */
|
||||
/* Optionally set verify_cb to a suitable non-NULL callback. */
|
||||
|
||||
/* Optionally set verify_cb to a suitable non-NULL callback. */
|
||||
SSL_set_verify(ssl, SSL_VERIFY_NONE, verify_cb);
|
||||
} else {
|
||||
/* At least one usable record. We expect to verify the peer */
|
||||
/*
|
||||
* Below we elect to fail the handshake when peer verification fails.
|
||||
* Alternatively, use the permissive SSL_VERIFY_NONE verification mode,
|
||||
* complete the handshake, check the verification status, and if not
|
||||
* verified disconnect gracefully at the application layer, especially if
|
||||
* application protocol supports informing the server that authentication
|
||||
* failed.
|
||||
*/
|
||||
SSL_set_verify(ssl, SSL_VERIFY_PEER, verify_cb);
|
||||
}
|
||||
|
||||
/* Optionally set verify_cb to a suitable non-NULL callback. */
|
||||
/*
|
||||
* Load any saved session for resumption, making sure that the previous
|
||||
* session applied the same security and authentication requirements that
|
||||
* would be expected of a fresh connection.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Below we elect to fail the handshake when peer verification fails.
|
||||
* Alternatively, use the permissive SSL_VERIFY_NONE verification mode,
|
||||
* complete the handshake, check the verification status, and if not
|
||||
* verified disconnect gracefully at the application layer, especially if
|
||||
* application protocol supports informing the server that authentication
|
||||
* failed.
|
||||
*/
|
||||
SSL_set_verify(ssl, SSL_VERIFY_PEER, verify_cb);
|
||||
}
|
||||
/* Perform SSL_connect() handshake and handle errors here */
|
||||
|
||||
/*
|
||||
* Load any saved session for resumption, making sure that the previous
|
||||
* session applied the same security and authentication requirements that
|
||||
* would be expected of a fresh connection.
|
||||
*/
|
||||
if (SSL_session_reused(ssl)) {
|
||||
if (SSL_get_verify_result(ssl) == X509_V_OK) {
|
||||
/*
|
||||
* Resumed session was originally verified, this connection is
|
||||
* authenticated.
|
||||
*/
|
||||
} else {
|
||||
/*
|
||||
* Resumed session was not originally verified, this connection is not
|
||||
* authenticated.
|
||||
*/
|
||||
}
|
||||
} else if (SSL_get_verify_result(ssl) == X509_V_OK) {
|
||||
const char *peername = SSL_get0_peername(ssl);
|
||||
EVP_PKEY *mspki = NULL;
|
||||
|
||||
/* Perform SSL_connect() handshake and handle errors here */
|
||||
|
||||
if (SSL_session_reused(ssl)) {
|
||||
if (SSL_get_verify_result(ssl) == X509_V_OK) {
|
||||
/*
|
||||
* Resumed session was originally verified, this connection is
|
||||
* authenticated.
|
||||
*/
|
||||
} else {
|
||||
/*
|
||||
* Resumed session was not originally verified, this connection is not
|
||||
* authenticated.
|
||||
*/
|
||||
}
|
||||
} else if (SSL_get_verify_result(ssl) == X509_V_OK) {
|
||||
const char *peername = SSL_get0_peername(ssl);
|
||||
EVP_PKEY *mspki = NULL;
|
||||
|
||||
int depth = SSL_get0_dane_authority(ssl, NULL, &mspki);
|
||||
if (depth >= 0) {
|
||||
(void) SSL_get0_dane_tlsa(ssl, &usage, &selector, &mtype, NULL, NULL);
|
||||
printf("DANE TLSA %d %d %d %s at depth %d\n", usage, selector, mtype,
|
||||
(mspki != NULL) ? "TA public key verified certificate" :
|
||||
depth ? "matched TA certificate" : "matched EE certificate",
|
||||
depth);
|
||||
}
|
||||
if (peername != NULL) {
|
||||
/* Name checks were in scope and matched the peername */
|
||||
printf("Verified peername: %s\n", peername);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Not authenticated, presumably all TLSA rrs unusable, but possibly a
|
||||
* callback suppressed connection termination despite the presence of
|
||||
* usable TLSA RRs none of which matched. Do whatever is appropriate for
|
||||
* fresh unauthenticated connections.
|
||||
*/
|
||||
}
|
||||
int depth = SSL_get0_dane_authority(ssl, NULL, &mspki);
|
||||
if (depth >= 0) {
|
||||
(void) SSL_get0_dane_tlsa(ssl, &usage, &selector, &mtype, NULL, NULL);
|
||||
printf("DANE TLSA %d %d %d %s at depth %d\n", usage, selector, mtype,
|
||||
(mspki != NULL) ? "TA public key verified certificate" :
|
||||
depth ? "matched TA certificate" : "matched EE certificate",
|
||||
depth);
|
||||
}
|
||||
if (peername != NULL) {
|
||||
/* Name checks were in scope and matched the peername */
|
||||
printf("Verified peername: %s\n", peername);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Not authenticated, presumably all TLSA rrs unusable, but possibly a
|
||||
* callback suppressed connection termination despite the presence of
|
||||
* usable TLSA RRs none of which matched. Do whatever is appropriate for
|
||||
* fresh unauthenticated connections.
|
||||
*/
|
||||
}
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ ca1.pem ca2.pem ca3.pem:
|
|||
#!/bin/sh
|
||||
rm CAfile.pem
|
||||
for i in ca1.pem ca2.pem ca3.pem ; do
|
||||
openssl x509 -in $i -text >> CAfile.pem
|
||||
openssl x509 -in $i -text >> CAfile.pem
|
||||
done
|
||||
|
||||
Prepare the directory /some/where/certs containing several CA certificates
|
||||
|
|
|
@ -86,14 +86,14 @@ The use of MD5 as a digest is strongly discouraged due to security weaknesses.
|
|||
Set supported signature algorithms to SHA256 with ECDSA and SHA256 with RSA
|
||||
using an array:
|
||||
|
||||
const int slist[] = {NID_sha256, EVP_PKEY_EC, NID_sha256, EVP_PKEY_RSA};
|
||||
const int slist[] = {NID_sha256, EVP_PKEY_EC, NID_sha256, EVP_PKEY_RSA};
|
||||
|
||||
SSL_CTX_set1_sigalgs(ctx, slist, 4);
|
||||
SSL_CTX_set1_sigalgs(ctx, slist, 4);
|
||||
|
||||
Set supported signature algorithms to SHA256 with ECDSA and SHA256 with RSA
|
||||
using a string:
|
||||
|
||||
SSL_CTX_set1_sigalgs_list(ctx, "ECDSA+SHA256:RSA+SHA256");
|
||||
SSL_CTX_set1_sigalgs_list(ctx, "ECDSA+SHA256:RSA+SHA256");
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ The operation succeeded.
|
|||
|
||||
Scan all certificates in B<CAfile> and list them as acceptable CAs:
|
||||
|
||||
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CAfile));
|
||||
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CAfile));
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
|
|
@ -85,9 +85,9 @@ truncated.
|
|||
|
||||
int my_cb(char *buf, int size, int rwflag, void *u)
|
||||
{
|
||||
strncpy(buf, (char *)u, size);
|
||||
buf[size - 1] = '\0';
|
||||
return strlen(buf);
|
||||
strncpy(buf, (char *)u, size);
|
||||
buf[size - 1] = '\0';
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
=head1 HISTORY
|
||||
|
|
|
@ -91,28 +91,26 @@ server id given, and will fill the rest with pseudo random bytes:
|
|||
|
||||
#define MAX_SESSION_ID_ATTEMPTS 10
|
||||
static int generate_session_id(const SSL *ssl, unsigned char *id,
|
||||
unsigned int *id_len)
|
||||
unsigned int *id_len)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
do {
|
||||
RAND_pseudo_bytes(id, *id_len);
|
||||
/*
|
||||
* Prefix the session_id with the required prefix. NB: If our
|
||||
* prefix is too long, clip it - but there will be worse effects
|
||||
* anyway, eg. the server could only possibly create 1 session
|
||||
* ID (ie. the prefix!) so all future session negotiations will
|
||||
* fail due to conflicts.
|
||||
*/
|
||||
memcpy(id, session_id_prefix,
|
||||
(strlen(session_id_prefix) < *id_len) ?
|
||||
strlen(session_id_prefix) : *id_len);
|
||||
}
|
||||
while (SSL_has_matching_session_id(ssl, id, *id_len) &&
|
||||
(++count < MAX_SESSION_ID_ATTEMPTS));
|
||||
if (count >= MAX_SESSION_ID_ATTEMPTS)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
unsigned int count = 0;
|
||||
do {
|
||||
RAND_pseudo_bytes(id, *id_len);
|
||||
/*
|
||||
* Prefix the session_id with the required prefix. NB: If our
|
||||
* prefix is too long, clip it - but there will be worse effects
|
||||
* anyway, eg. the server could only possibly create 1 session
|
||||
* ID (ie. the prefix!) so all future session negotiations will
|
||||
* fail due to conflicts.
|
||||
*/
|
||||
memcpy(id, session_id_prefix, strlen(session_id_prefix) < *id_len ?
|
||||
strlen(session_id_prefix) : *id_len);
|
||||
} while (SSL_has_matching_session_id(ssl, id, *id_len)
|
||||
&& ++count < MAX_SESSION_ID_ATTEMPTS);
|
||||
if (count >= MAX_SESSION_ID_ATTEMPTS)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
|
|
@ -110,40 +110,34 @@ The following example callback function prints state strings, information
|
|||
about alerts being handled and error messages to the B<bio_err> BIO.
|
||||
|
||||
void apps_ssl_info_callback(SSL *s, int where, int ret)
|
||||
{
|
||||
const char *str;
|
||||
int w;
|
||||
{
|
||||
const char *str;
|
||||
int w = where & ~SSL_ST_MASK;
|
||||
|
||||
w = where & ~SSL_ST_MASK;
|
||||
if (w & SSL_ST_CONNECT)
|
||||
str = "SSL_connect";
|
||||
else if (w & SSL_ST_ACCEPT)
|
||||
str = "SSL_accept";
|
||||
else
|
||||
str = "undefined";
|
||||
|
||||
if (w & SSL_ST_CONNECT) str = "SSL_connect";
|
||||
else if (w & SSL_ST_ACCEPT) str = "SSL_accept";
|
||||
else str = "undefined";
|
||||
|
||||
if (where & SSL_CB_LOOP)
|
||||
{
|
||||
BIO_printf(bio_err, "%s:%s\n", str, SSL_state_string_long(s));
|
||||
}
|
||||
else if (where & SSL_CB_ALERT)
|
||||
{
|
||||
str = (where & SSL_CB_READ) ? "read" : "write";
|
||||
BIO_printf(bio_err, "SSL3 alert %s:%s:%s\n",
|
||||
str,
|
||||
SSL_alert_type_string_long(ret),
|
||||
SSL_alert_desc_string_long(ret));
|
||||
}
|
||||
else if (where & SSL_CB_EXIT)
|
||||
{
|
||||
if (ret == 0)
|
||||
BIO_printf(bio_err, "%s:failed in %s\n",
|
||||
str, SSL_state_string_long(s));
|
||||
else if (ret < 0)
|
||||
{
|
||||
BIO_printf(bio_err, "%s:error in %s\n",
|
||||
str, SSL_state_string_long(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (where & SSL_CB_LOOP) {
|
||||
BIO_printf(bio_err, "%s:%s\n", str, SSL_state_string_long(s));
|
||||
} else if (where & SSL_CB_ALERT) {
|
||||
str = (where & SSL_CB_READ) ? "read" : "write";
|
||||
BIO_printf(bio_err, "SSL3 alert %s:%s:%s\n", str,
|
||||
SSL_alert_type_string_long(ret),
|
||||
SSL_alert_desc_string_long(ret));
|
||||
} else if (where & SSL_CB_EXIT) {
|
||||
if (ret == 0) {
|
||||
BIO_printf(bio_err, "%s:failed in %s\n",
|
||||
str, SSL_state_string_long(s));
|
||||
} else if (ret < 0) {
|
||||
BIO_printf(bio_err, "%s:error in %s\n",
|
||||
str, SSL_state_string_long(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
|
|
@ -124,51 +124,56 @@ enable an attacker to obtain the session keys.
|
|||
=head1 EXAMPLES
|
||||
|
||||
Reference Implementation:
|
||||
SSL_CTX_set_tlsext_ticket_key_cb(SSL, ssl_tlsext_ticket_key_cb);
|
||||
....
|
||||
|
||||
static int ssl_tlsext_ticket_key_cb(SSL *s, unsigned char key_name[16], unsigned char *iv, EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc)
|
||||
{
|
||||
if (enc) { /* create new session */
|
||||
if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) )
|
||||
return -1; /* insufficient random */
|
||||
SSL_CTX_set_tlsext_ticket_key_cb(SSL, ssl_tlsext_ticket_key_cb);
|
||||
...
|
||||
|
||||
key = currentkey(); /* something that you need to implement */
|
||||
if ( key == NULL ) {
|
||||
/* current key doesn't exist or isn't valid */
|
||||
key = createkey(); /* something that you need to implement.
|
||||
* createkey needs to initialise, a name,
|
||||
* an aes_key, a hmac_key and optionally
|
||||
* an expire time. */
|
||||
if ( key == NULL ) /* key couldn't be created */
|
||||
return 0;
|
||||
}
|
||||
memcpy(key_name, key->name, 16);
|
||||
static int ssl_tlsext_ticket_key_cb(SSL *s, unsigned char key_name[16],
|
||||
unsigned char *iv, EVP_CIPHER_CTX *ctx,
|
||||
HMAC_CTX *hctx, int enc)
|
||||
{
|
||||
if (enc) { /* create new session */
|
||||
if (RAND_bytes(iv, EVP_MAX_IV_LENGTH))
|
||||
return -1; /* insufficient random */
|
||||
|
||||
EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key->aes_key, iv);
|
||||
HMAC_Init_ex(&hctx, key->hmac_key, 16, EVP_sha256(), NULL);
|
||||
key = currentkey(); /* something that you need to implement */
|
||||
if (key == NULL) {
|
||||
/* current key doesn't exist or isn't valid */
|
||||
key = createkey(); /*
|
||||
* Something that you need to implement.
|
||||
* createkey needs to initialise a name,
|
||||
* an aes_key, a hmac_key and optionally
|
||||
* an expire time.
|
||||
*/
|
||||
if (key == NULL) /* key couldn't be created */
|
||||
return 0;
|
||||
}
|
||||
memcpy(key_name, key->name, 16);
|
||||
|
||||
return 1;
|
||||
EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key->aes_key, iv);
|
||||
HMAC_Init_ex(&hctx, key->hmac_key, 16, EVP_sha256(), NULL);
|
||||
|
||||
} else { /* retrieve session */
|
||||
key = findkey(name);
|
||||
return 1;
|
||||
|
||||
if (key == NULL || key->expire < now() )
|
||||
return 0;
|
||||
} else { /* retrieve session */
|
||||
key = findkey(name);
|
||||
|
||||
HMAC_Init_ex(&hctx, key->hmac_key, 16, EVP_sha256(), NULL);
|
||||
EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key->aes_key, iv );
|
||||
|
||||
if (key->expire < ( now() - RENEW_TIME ) )
|
||||
/* return 2 - this session will get a new ticket even though the current is still valid */
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
}
|
||||
if (key == NULL || key->expire < now())
|
||||
return 0;
|
||||
|
||||
HMAC_Init_ex(&hctx, key->hmac_key, 16, EVP_sha256(), NULL);
|
||||
EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key->aes_key, iv);
|
||||
|
||||
if (key->expire < now() - RENEW_TIME) {
|
||||
/*
|
||||
* return 2 - This session will get a new ticket even though the
|
||||
* current one is still valid.
|
||||
*/
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
|
|
|
@ -84,31 +84,27 @@ supply at least 2048-bit parameters in the callback.
|
|||
Setup DH parameters with a key length of 2048 bits. (Error handling
|
||||
partly left out.)
|
||||
|
||||
Command-line parameter generation:
|
||||
Command-line parameter generation:
|
||||
|
||||
$ openssl dhparam -out dh_param_2048.pem 2048
|
||||
|
||||
Code for setting up parameters during server initialization:
|
||||
Code for setting up parameters during server initialization:
|
||||
|
||||
...
|
||||
SSL_CTX ctx = SSL_CTX_new();
|
||||
...
|
||||
|
||||
/* Set up ephemeral DH parameters. */
|
||||
DH *dh_2048 = NULL;
|
||||
FILE *paramfile;
|
||||
paramfile = fopen("dh_param_2048.pem", "r");
|
||||
if (paramfile) {
|
||||
dh_2048 = PEM_read_DHparams(paramfile, NULL, NULL, NULL);
|
||||
fclose(paramfile);
|
||||
dh_2048 = PEM_read_DHparams(paramfile, NULL, NULL, NULL);
|
||||
fclose(paramfile);
|
||||
} else {
|
||||
/* Error. */
|
||||
}
|
||||
if (dh_2048 == NULL) {
|
||||
/* Error. */
|
||||
}
|
||||
if (SSL_CTX_set_tmp_dh(ctx, dh_2048) != 1) {
|
||||
/* Error. */
|
||||
/* Error. */
|
||||
}
|
||||
if (dh_2048 == NULL)
|
||||
/* Error. */
|
||||
if (SSL_CTX_set_tmp_dh(ctx, dh_2048) != 1)
|
||||
/* Error. */
|
||||
...
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
|
|
@ -190,65 +190,63 @@ L<SSL_get_ex_data_X509_STORE_CTX_idx(3)>).
|
|||
int always_continue;
|
||||
} mydata_t;
|
||||
int mydata_index;
|
||||
|
||||
...
|
||||
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
char buf[256];
|
||||
X509 *err_cert;
|
||||
int err, depth;
|
||||
SSL *ssl;
|
||||
mydata_t *mydata;
|
||||
char buf[256];
|
||||
X509 *err_cert;
|
||||
int err, depth;
|
||||
SSL *ssl;
|
||||
mydata_t *mydata;
|
||||
|
||||
err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||
err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||
|
||||
/*
|
||||
* Retrieve the pointer to the SSL of the connection currently treated
|
||||
* and the application specific data stored into the SSL object.
|
||||
*/
|
||||
ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||
mydata = SSL_get_ex_data(ssl, mydata_index);
|
||||
/*
|
||||
* Retrieve the pointer to the SSL of the connection currently treated
|
||||
* and the application specific data stored into the SSL object.
|
||||
*/
|
||||
ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||
mydata = SSL_get_ex_data(ssl, mydata_index);
|
||||
|
||||
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
|
||||
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
|
||||
|
||||
/*
|
||||
* Catch a too long certificate chain. The depth limit set using
|
||||
* SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
|
||||
* that whenever the "depth>verify_depth" condition is met, we
|
||||
* have violated the limit and want to log this error condition.
|
||||
* We must do it here, because the CHAIN_TOO_LONG error would not
|
||||
* be found explicitly; only errors introduced by cutting off the
|
||||
* additional certificates would be logged.
|
||||
*/
|
||||
if (depth > mydata->verify_depth) {
|
||||
preverify_ok = 0;
|
||||
err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
|
||||
X509_STORE_CTX_set_error(ctx, err);
|
||||
}
|
||||
if (!preverify_ok) {
|
||||
printf("verify error:num=%d:%s:depth=%d:%s\n", err,
|
||||
X509_verify_cert_error_string(err), depth, buf);
|
||||
}
|
||||
else if (mydata->verbose_mode)
|
||||
{
|
||||
printf("depth=%d:%s\n", depth, buf);
|
||||
}
|
||||
/*
|
||||
* Catch a too long certificate chain. The depth limit set using
|
||||
* SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
|
||||
* that whenever the "depth>verify_depth" condition is met, we
|
||||
* have violated the limit and want to log this error condition.
|
||||
* We must do it here, because the CHAIN_TOO_LONG error would not
|
||||
* be found explicitly; only errors introduced by cutting off the
|
||||
* additional certificates would be logged.
|
||||
*/
|
||||
if (depth > mydata->verify_depth) {
|
||||
preverify_ok = 0;
|
||||
err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
|
||||
X509_STORE_CTX_set_error(ctx, err);
|
||||
}
|
||||
if (!preverify_ok) {
|
||||
printf("verify error:num=%d:%s:depth=%d:%s\n", err,
|
||||
X509_verify_cert_error_string(err), depth, buf);
|
||||
} else if (mydata->verbose_mode) {
|
||||
printf("depth=%d:%s\n", depth, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, err contains the last verification error. We can use
|
||||
* it for something special
|
||||
*/
|
||||
if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
|
||||
{
|
||||
X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, 256);
|
||||
printf("issuer= %s\n", buf);
|
||||
}
|
||||
/*
|
||||
* At this point, err contains the last verification error. We can use
|
||||
* it for something special
|
||||
*/
|
||||
if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
|
||||
X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, 256);
|
||||
printf("issuer= %s\n", buf);
|
||||
}
|
||||
|
||||
if (mydata->always_continue)
|
||||
return 1;
|
||||
else
|
||||
return preverify_ok;
|
||||
if (mydata->always_continue)
|
||||
return 1;
|
||||
else
|
||||
return preverify_ok;
|
||||
}
|
||||
...
|
||||
|
||||
|
@ -258,7 +256,7 @@ L<SSL_get_ex_data_X509_STORE_CTX_idx(3)>).
|
|||
mydata_index = SSL_get_ex_new_index(0, "mydata index", NULL, NULL, NULL);
|
||||
|
||||
...
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
|
||||
verify_callback);
|
||||
|
||||
/*
|
||||
|
@ -276,12 +274,10 @@ L<SSL_get_ex_data_X509_STORE_CTX_idx(3)>).
|
|||
|
||||
...
|
||||
SSL_accept(ssl); /* check of success left out for clarity */
|
||||
if (peer = SSL_get_peer_certificate(ssl))
|
||||
{
|
||||
if (SSL_get_verify_result(ssl) == X509_V_OK)
|
||||
{
|
||||
/* The client sent a certificate which verified OK */
|
||||
}
|
||||
if (peer = SSL_get_peer_certificate(ssl)) {
|
||||
if (SSL_get_verify_result(ssl) == X509_V_OK) {
|
||||
/* The client sent a certificate which verified OK */
|
||||
}
|
||||
}
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
|
|
@ -33,9 +33,9 @@ Load names of CAs from file and use it as a client CA list:
|
|||
...
|
||||
cert_names = SSL_load_client_CA_file("/path/to/CAfile.pem");
|
||||
if (cert_names != NULL)
|
||||
SSL_CTX_set_client_CA_list(ctx, cert_names);
|
||||
SSL_CTX_set_client_CA_list(ctx, cert_names);
|
||||
else
|
||||
error_handling();
|
||||
/* error */
|
||||
...
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
|
|
@ -81,23 +81,20 @@ matched in the certificate (which might be a wildcard) is retrieved,
|
|||
and must be copied by the application if it is to be retained beyond
|
||||
the lifetime of the SSL connection.
|
||||
|
||||
SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
if (!SSL_set1_host(ssl, "smtp.example.com")) {
|
||||
/* handle error */
|
||||
}
|
||||
if (!SSL_add1_host(ssl, "example.com")) {
|
||||
/* handle error */
|
||||
}
|
||||
SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
if (!SSL_set1_host(ssl, "smtp.example.com"))
|
||||
/* error */
|
||||
if (!SSL_add1_host(ssl, "example.com"))
|
||||
/* error */
|
||||
|
||||
/* XXX: Perform SSL_connect() handshake and handle errors here */
|
||||
/* XXX: Perform SSL_connect() handshake and handle errors here */
|
||||
|
||||
if (SSL_get_verify_result(ssl) == X509_V_OK) {
|
||||
const char *peername = SSL_get0_peername(ssl);
|
||||
if (SSL_get_verify_result(ssl) == X509_V_OK) {
|
||||
const char *peername = SSL_get0_peername(ssl);
|
||||
|
||||
if (peername != NULL) {
|
||||
/* Name checks were in scope and matched the peername */
|
||||
}
|
||||
}
|
||||
if (peername != NULL)
|
||||
/* Name checks were in scope and matched the peername */
|
||||
}
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
|
|
@ -80,16 +80,16 @@ Create an B<X509_NAME> structure:
|
|||
X509_NAME *nm;
|
||||
nm = X509_NAME_new();
|
||||
if (nm == NULL)
|
||||
/* Some error */
|
||||
/* Some error */
|
||||
if (!X509_NAME_add_entry_by_txt(nm, "C", MBSTRING_ASC,
|
||||
"UK", -1, -1, 0))
|
||||
/* Error */
|
||||
"UK", -1, -1, 0))
|
||||
/* Error */
|
||||
if (!X509_NAME_add_entry_by_txt(nm, "O", MBSTRING_ASC,
|
||||
"Disorganized Organization", -1, -1, 0))
|
||||
/* Error */
|
||||
"Disorganized Organization", -1, -1, 0))
|
||||
/* Error */
|
||||
if (!X509_NAME_add_entry_by_txt(nm, "CN", MBSTRING_ASC,
|
||||
"Joe Bloggs", -1, -1, 0))
|
||||
/* Error */
|
||||
"Joe Bloggs", -1, -1, 0))
|
||||
/* Error */
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
|
|
|
@ -75,25 +75,23 @@ Process all entries:
|
|||
int i;
|
||||
X509_NAME_ENTRY *e;
|
||||
|
||||
for (i = 0; i < X509_NAME_entry_count(nm); i++)
|
||||
{
|
||||
e = X509_NAME_get_entry(nm, i);
|
||||
/* Do something with e */
|
||||
}
|
||||
for (i = 0; i < X509_NAME_entry_count(nm); i++) {
|
||||
e = X509_NAME_get_entry(nm, i);
|
||||
/* Do something with e */
|
||||
}
|
||||
|
||||
Process all commonName entries:
|
||||
|
||||
int lastpos = -1;
|
||||
X509_NAME_ENTRY *e;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
lastpos = X509_NAME_get_index_by_NID(nm, NID_commonName, lastpos);
|
||||
if (lastpos == -1)
|
||||
break;
|
||||
e = X509_NAME_get_entry(nm, lastpos);
|
||||
/* Do something with e */
|
||||
}
|
||||
for (;;) {
|
||||
lastpos = X509_NAME_get_index_by_NID(nm, NID_commonName, lastpos);
|
||||
if (lastpos == -1)
|
||||
break;
|
||||
e = X509_NAME_get_entry(nm, lastpos);
|
||||
/* Do something with e */
|
||||
}
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ is B<not> successful the returned chain may be incomplete or invalid. The
|
|||
returned chain persists after the B<ctx> structure is freed, when it is
|
||||
no longer needed it should be free up using:
|
||||
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
|
||||
X509_verify_cert_error_string() returns a human readable error string for
|
||||
verification error B<n>.
|
||||
|
|
|
@ -100,93 +100,88 @@ X509_STORE_CTX_set_verify_cb() does not return a value.
|
|||
|
||||
Default callback operation:
|
||||
|
||||
int verify_callback(int ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
return ok;
|
||||
}
|
||||
int verify_callback(int ok, X509_STORE_CTX *ctx) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
Simple example, suppose a certificate in the chain is expired and we wish
|
||||
to continue after this error:
|
||||
|
||||
int verify_callback(int ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
/* Tolerate certificate expiration */
|
||||
if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED)
|
||||
return 1;
|
||||
/* Otherwise don't override */
|
||||
return ok;
|
||||
}
|
||||
int verify_callback(int ok, X509_STORE_CTX *ctx) {
|
||||
/* Tolerate certificate expiration */
|
||||
if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED)
|
||||
return 1;
|
||||
/* Otherwise don't override */
|
||||
return ok;
|
||||
}
|
||||
|
||||
More complex example, we don't wish to continue after B<any> certificate has
|
||||
expired just one specific case:
|
||||
|
||||
int verify_callback(int ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
int err = X509_STORE_CTX_get_error(ctx);
|
||||
X509 *err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
if (err == X509_V_ERR_CERT_HAS_EXPIRED)
|
||||
{
|
||||
if (check_is_acceptable_expired_cert(err_cert)
|
||||
return 1;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
{
|
||||
int err = X509_STORE_CTX_get_error(ctx);
|
||||
X509 *err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
if (err == X509_V_ERR_CERT_HAS_EXPIRED) {
|
||||
if (check_is_acceptable_expired_cert(err_cert)
|
||||
return 1;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
Full featured logging callback. In this case the B<bio_err> is assumed to be
|
||||
a global logging B<BIO>, an alternative would to store a BIO in B<ctx> using
|
||||
B<ex_data>.
|
||||
|
||||
int verify_callback(int ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
X509 *err_cert;
|
||||
int err, depth;
|
||||
{
|
||||
X509 *err_cert;
|
||||
int err, depth;
|
||||
|
||||
err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||
err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||
|
||||
BIO_printf(bio_err, "depth=%d ", depth);
|
||||
if (err_cert)
|
||||
{
|
||||
X509_NAME_print_ex(bio_err, X509_get_subject_name(err_cert),
|
||||
0, XN_FLAG_ONELINE);
|
||||
BIO_puts(bio_err, "\n");
|
||||
}
|
||||
else
|
||||
BIO_puts(bio_err, "<no cert>\n");
|
||||
if (!ok)
|
||||
BIO_printf(bio_err, "verify error:num=%d:%s\n", err,
|
||||
X509_verify_cert_error_string(err));
|
||||
switch (err)
|
||||
{
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
BIO_puts(bio_err, "issuer= ");
|
||||
X509_NAME_print_ex(bio_err, X509_get_issuer_name(err_cert),
|
||||
0, XN_FLAG_ONELINE);
|
||||
BIO_puts(bio_err, "\n");
|
||||
break;
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
BIO_printf(bio_err, "notBefore=");
|
||||
ASN1_TIME_print(bio_err, X509_get_notBefore(err_cert));
|
||||
BIO_printf(bio_err, "\n");
|
||||
break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
BIO_printf(bio_err, "notAfter=");
|
||||
ASN1_TIME_print(bio_err, X509_get_notAfter(err_cert));
|
||||
BIO_printf(bio_err, "\n");
|
||||
break;
|
||||
case X509_V_ERR_NO_EXPLICIT_POLICY:
|
||||
policies_print(bio_err, ctx);
|
||||
break;
|
||||
}
|
||||
if (err == X509_V_OK && ok == 2)
|
||||
/* print out policies */
|
||||
BIO_printf(bio_err, "depth=%d ", depth);
|
||||
if (err_cert) {
|
||||
X509_NAME_print_ex(bio_err, X509_get_subject_name(err_cert),
|
||||
0, XN_FLAG_ONELINE);
|
||||
BIO_puts(bio_err, "\n");
|
||||
}
|
||||
else
|
||||
BIO_puts(bio_err, "<no cert>\n");
|
||||
if (!ok)
|
||||
BIO_printf(bio_err, "verify error:num=%d:%s\n", err,
|
||||
X509_verify_cert_error_string(err));
|
||||
switch (err) {
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
BIO_puts(bio_err, "issuer= ");
|
||||
X509_NAME_print_ex(bio_err, X509_get_issuer_name(err_cert),
|
||||
0, XN_FLAG_ONELINE);
|
||||
BIO_puts(bio_err, "\n");
|
||||
break;
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
BIO_printf(bio_err, "notBefore=");
|
||||
ASN1_TIME_print(bio_err, X509_get_notBefore(err_cert));
|
||||
BIO_printf(bio_err, "\n");
|
||||
break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
BIO_printf(bio_err, "notAfter=");
|
||||
ASN1_TIME_print(bio_err, X509_get_notAfter(err_cert));
|
||||
BIO_printf(bio_err, "\n");
|
||||
break;
|
||||
case X509_V_ERR_NO_EXPLICIT_POLICY:
|
||||
policies_print(bio_err, ctx);
|
||||
break;
|
||||
}
|
||||
if (err == X509_V_OK && ok == 2)
|
||||
/* print out policies */
|
||||
|
||||
BIO_printf(bio_err, "verify return:%d\n", ok);
|
||||
return(ok);
|
||||
}
|
||||
BIO_printf(bio_err, "verify return:%d\n", ok);
|
||||
return(ok);
|
||||
}
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
|
|
@ -310,11 +310,11 @@ CRLs from the CRL distribution points extension.
|
|||
Enable CRL checking when performing certificate verification during SSL
|
||||
connections associated with an B<SSL_CTX> structure B<ctx>:
|
||||
|
||||
X509_VERIFY_PARAM *param;
|
||||
param = X509_VERIFY_PARAM_new();
|
||||
X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK);
|
||||
SSL_CTX_set1_param(ctx, param);
|
||||
X509_VERIFY_PARAM_free(param);
|
||||
X509_VERIFY_PARAM *param;
|
||||
param = X509_VERIFY_PARAM_new();
|
||||
X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK);
|
||||
SSL_CTX_set1_param(ctx, param);
|
||||
X509_VERIFY_PARAM_free(param);
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
|
Loading…
Reference in a new issue