diff --git a/crypto/engine/hw_cryptodev.c b/crypto/engine/hw_cryptodev.c new file mode 100644 index 000000000..df887b03d --- /dev/null +++ b/crypto/engine/hw_cryptodev.c @@ -0,0 +1,1117 @@ +/* + * Copyright (c) 2002 Bob Beck + * Copyright (c) 2002 Theo de Raadt + * Copyright (c) 2002 Markus Friedl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#ifndef __OpenBSD__ + +void +ENGINE_load_cryptodev(void) +{ + /* This is a NOP unless __OpenBSD__ is defined */ + return; +} + +#else /* __OpenBSD__ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct dev_crypto_state { + struct session_op d_sess; + int d_fd; +}; + +static u_int32_t cryptodev_asymfeat = 0; + +static int get_asym_dev_crypto(void); +static int open_dev_crypto(void); +static int get_dev_crypto(void); +static int cryptodev_max_iv(int cipher); +static int cryptodev_key_length_valid(int cipher, int len); +static int cipher_nid_to_cryptodev(int nid); +static int get_cryptodev_ciphers(const int **cnids); +static int get_cryptodev_digests(const int **cnids); +static int cryptodev_usable_ciphers(const int **nids); +static int cryptodev_usable_digests(const int **nids); +static int cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl); +static int cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc); +static int cryptodev_cleanup(EVP_CIPHER_CTX *ctx); +static int cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher, + const int **nids, int nid); +static int cryptodev_engine_digests(ENGINE *e, const EVP_MD **digest, + const int **nids, int nid); +static int bn2crparam(const BIGNUM *a, struct crparam *crp); +static int crparam2bn(struct crparam *crp, BIGNUM *a); +static void zapparams(struct crypt_kop *kop); +static int cryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r, + int slen, BIGNUM *s); + +static int cryptodev_bn_mod_exp(BIGNUM *r, const BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +static int cryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I, + RSA *rsa); +static int cryptodev_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa); +static int cryptodev_dsa_bn_mod_exp(DSA *dsa, BIGNUM *r, BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +static int cryptodev_dsa_dsa_mod_exp(DSA *dsa, BIGNUM *t1, BIGNUM *g, + BIGNUM *u1, BIGNUM *pub_key, BIGNUM *u2, BIGNUM *p, + BN_CTX *ctx, BN_MONT_CTX *mont); +static DSA_SIG *cryptodev_dsa_do_sign(const unsigned char *dgst, + int dlen, DSA *dsa); +static int cryptodev_dsa_verify(const unsigned char *dgst, int dgst_len, + DSA_SIG *sig, DSA *dsa); +static int cryptodev_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); +static int cryptodev_dh_compute_key(unsigned char *key, + const BIGNUM *pub_key, DH *dh); +static int cryptodev_ctrl(ENGINE *e, int cmd, long i, void *p, + void (*f)()); +void ENGINE_load_cryptodev(void); + +static const ENGINE_CMD_DEFN cryptodev_defns[] = { + { 0, NULL, NULL, 0 } +}; + +static struct { + int id; + int nid; + int ivmax; + int keylen; +} ciphers[] = { + { CRYPTO_DES_CBC, NID_des_cbc, 8, 8, }, + { CRYPTO_3DES_CBC, NID_des_ede3_cbc, 8, 24, }, + { CRYPTO_AES_CBC, NID_aes_128_cbc, 16, 16, }, + { CRYPTO_BLF_CBC, NID_bf_cbc, 8, 16, }, + { CRYPTO_CAST_CBC, NID_cast5_cbc, 8, 16, }, + { CRYPTO_SKIPJACK_CBC, NID_undef, 0, 0, }, + { 0, NID_undef, 0, 0, }, +}; + +static struct { + int id; + int nid; +} digests[] = { + { CRYPTO_SHA1_HMAC, NID_hmacWithSHA1, }, + { CRYPTO_RIPEMD160_HMAC, NID_ripemd160, }, + { CRYPTO_MD5_KPDK, NID_undef, }, + { CRYPTO_SHA1_KPDK, NID_undef, }, + { CRYPTO_MD5, NID_md5, }, + { CRYPTO_SHA1, NID_undef, }, + { 0, NID_undef, }, +}; + +/* + * Return a fd if /dev/crypto seems usable, 0 otherwise. + */ +static int +open_dev_crypto(void) +{ + static int fd = -1; + + if (fd == -1) { + if ((fd = open("/dev/crypto", O_RDWR, 0)) == -1) + return (-1); + /* close on exec */ + if (fcntl(fd, F_SETFD, 1) == -1) { + close(fd); + fd = -1; + return (-1); + } + } + return (fd); +} + +static int +get_dev_crypto(void) +{ + int fd, retfd; + + if ((fd = open_dev_crypto()) == -1) + return (-1); + if (ioctl(fd, CRIOGET, &retfd) == -1) + return (-1); + + /* close on exec */ + if (fcntl(retfd, F_SETFD, 1) == -1) { + close(retfd); + return (-1); + } + return (retfd); +} + +/* Caching version for asym operations */ +static int +get_asym_dev_crypto(void) +{ + static int fd = -1; + + if (fd == -1) + fd = get_dev_crypto(); + return fd; +} + +/* + * XXXX this needs to be set for each alg - and determined from + * a running card. + */ +static int +cryptodev_max_iv(int cipher) +{ + int i; + + for (i = 0; ciphers[i].id; i++) + if (ciphers[i].id == cipher) + return (ciphers[i].ivmax); + return (0); +} + +/* + * XXXX this needs to be set for each alg - and determined from + * a running card. For now, fake it out - but most of these + * for real devices should return 1 for the supported key + * sizes the device can handle. + */ +static int +cryptodev_key_length_valid(int cipher, int len) +{ + int i; + + for (i = 0; ciphers[i].id; i++) + if (ciphers[i].id == cipher) + return (ciphers[i].keylen == len); + return (0); +} + +/* convert libcrypto nids to cryptodev */ +static int +cipher_nid_to_cryptodev(int nid) +{ + int i; + + for (i = 0; ciphers[i].id; i++) + if (ciphers[i].nid == nid) + return (ciphers[i].id); + return (0); +} + +/* + * Find out what ciphers /dev/crypto will let us have a session for. + * XXX note, that some of these openssl doesn't deal with yet! + * returning them here is harmless, as long as we return NULL + * when asked for a handler in the cryptodev_engine_ciphers routine + */ +static int +get_cryptodev_ciphers(const int **cnids) +{ + static int nids[CRYPTO_ALGORITHM_MAX]; + struct session_op sess; + int fd, i, count = 0; + + if ((fd = get_dev_crypto()) < 0) { + *nids = NULL; + return (0); + } + memset(&sess, 0, sizeof(sess)); + sess.key = (caddr_t)"123456781234567812345678"; + + for (i = 0; ciphers[i].id && count < CRYPTO_ALGORITHM_MAX; i++) { + if (ciphers[i].nid == NID_undef) + continue; + sess.cipher = ciphers[i].id; + sess.keylen = ciphers[i].keylen; + sess.mac = 0; + if (ioctl(fd, CIOCGSESSION, &sess) != -1 && + ioctl(fd, CIOCFSESSION, &sess.ses) != -1) + nids[count++] = ciphers[i].nid; + } + close(fd); + + if (count > 0) + *cnids = nids; + else + *cnids = NULL; + return (count); +} + +/* + * Find out what digests /dev/crypto will let us have a session for. + * XXX note, that some of these openssl doesn't deal with yet! + * returning them here is harmless, as long as we return NULL + * when asked for a handler in the cryptodev_engine_digests routine + */ +static int +get_cryptodev_digests(const int **cnids) +{ + static int nids[CRYPTO_ALGORITHM_MAX]; + struct session_op sess; + int fd, i, count = 0; + + if ((fd = get_dev_crypto()) < 0) { + *nids = NULL; + return (0); + } + memset(&sess, 0, sizeof(sess)); + for (i = 0; digests[i].id && count < CRYPTO_ALGORITHM_MAX; i++) { + if (digests[i].nid == NID_undef) + continue; + sess.mac = digests[i].id; + sess.cipher = 0; + if (ioctl(fd, CIOCGSESSION, &sess) != -1 && + ioctl(fd, CIOCFSESSION, &sess.ses) != -1) + nids[count++] = digests[i].nid; + } + close(fd); + + if (count > 0) + *cnids = nids; + else + *cnids = NULL; + return (count); +} + +/* + * Find the useable ciphers|digests from dev/crypto - this is the first + * thing called by the engine init crud which determines what it + * can use for ciphers from this engine. We want to return + * only what we can do, anythine else is handled by software. + * + * If we can't initialize the device to do anything useful for + * any reason, we want to return a NULL array, and 0 length, + * which forces everything to be done is software. By putting + * the initalization of the device in here, we ensure we can + * use this engine as the default, and if for whatever reason + * /dev/crypto won't do what we want it will just be done in + * software + * + * This can (should) be greatly expanded to perhaps take into + * account speed of the device, and what we want to do. + * (although the disabling of particular alg's could be controlled + * by the device driver with sysctl's.) - this is where we + * want most of the decisions made about what we actually want + * to use from /dev/crypto. + */ +static int +cryptodev_usable_ciphers(const int **nids) +{ + return (get_cryptodev_ciphers(nids)); +} + +static int +cryptodev_usable_digests(const int **nids) +{ + /* + * XXXX just disable all digests for now, because it sucks. + * we need a better way to decide this - i.e. I may not + * want digests on slow cards like hifn on fast machines, + * but might want them on slow or loaded machines, etc. + * will also want them when using crypto cards that don't + * suck moose gonads - would be nice to be able to decide something + * as reasonable default without having hackery that's card dependent. + * of course, the default should probably be just do everything, + * with perhaps a sysctl to turn algoritms off (or have them off + * by default) on cards that generally suck like the hifn. + */ + *nids = NULL; + return (0); +} + +static int +cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl) +{ + struct crypt_op cryp; + struct dev_crypto_state *state = ctx->cipher_data; + struct session_op *sess = &state->d_sess; + void *iiv; + unsigned char save_iv[EVP_MAX_IV_LENGTH]; + + if (state->d_fd < 0) + return (0); + if (!inl) + return (1); + if ((inl % ctx->cipher->block_size) != 0) + return (0); + + memset(&cryp, 0, sizeof(cryp)); + + cryp.ses = sess->ses; + cryp.flags = 0; + cryp.len = inl; + cryp.src = (caddr_t) in; + cryp.dst = (caddr_t) out; + cryp.mac = 0; + + cryp.op = ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT; + + if (ctx->cipher->iv_len) { + cryp.iv = (caddr_t) ctx->iv; + if (!ctx->encrypt) { + iiv = (void *) in + inl - ctx->cipher->iv_len; + memcpy(save_iv, iiv, ctx->cipher->iv_len); + } + } else + cryp.iv = NULL; + + if (ioctl(state->d_fd, CIOCCRYPT, &cryp) == -1) { + /* XXX need better errror handling + * this can fail for a number of different reasons. + */ + return (0); + } + + if (ctx->cipher->iv_len) { + if (ctx->encrypt) + iiv = (void *) out + inl - ctx->cipher->iv_len; + else + iiv = save_iv; + memcpy(ctx->iv, iiv, ctx->cipher->iv_len); + } + return (1); +} + +static int +cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) +{ + struct dev_crypto_state *state = ctx->cipher_data; + struct session_op *sess = &state->d_sess; + int cipher; + + if ((cipher = cipher_nid_to_cryptodev(ctx->cipher->nid)) == NID_undef) + return (0); + + if (ctx->cipher->iv_len > cryptodev_max_iv(cipher)) + return (0); + + if (!cryptodev_key_length_valid(cipher, ctx->key_len)) + return (0); + + memset(sess, 0, sizeof(struct session_op)); + + if ((state->d_fd = get_dev_crypto()) < 0) + return (0); + + sess->key = (unsigned char *)key; + sess->keylen = ctx->key_len; + sess->cipher = cipher; + + if (ioctl(state->d_fd, CIOCGSESSION, sess) == -1) { + close(state->d_fd); + state->d_fd = -1; + return (0); + } + return (1); +} + +/* + * free anything we allocated earlier when initting a + * session, and close the session. + */ +static int +cryptodev_cleanup(EVP_CIPHER_CTX *ctx) +{ + int ret = 0; + struct dev_crypto_state *state = ctx->cipher_data; + struct session_op *sess = &state->d_sess; + + if (state->d_fd < 0) + return (0); + + /* XXX if this ioctl fails, someting's wrong. the invoker + * may have called us with a bogus ctx, or we could + * have a device that for whatever reason just doesn't + * want to play ball - it's not clear what's right + * here - should this be an error? should it just + * increase a counter, hmm. For right now, we return + * 0 - I don't believe that to be "right". we could + * call the gorpy openssl lib error handlers that + * print messages to users of the library. hmm.. + */ + + if (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) == -1) { + ret = 0; + } else { + ret = 1; + } + close(state->d_fd); + state->d_fd = -1; + + return (ret); +} + +/* + * libcrypto EVP stuff - this is how we get wired to EVP so the engine + * gets called when libcrypto requests a cipher NID. + */ + +/* DES CBC EVP */ +const EVP_CIPHER cryptodev_des_cbc = { + NID_des_cbc, + 8, 8, 8, + EVP_CIPH_CBC_MODE, + cryptodev_init_key, + cryptodev_cipher, + cryptodev_cleanup, + sizeof(struct dev_crypto_state), + EVP_CIPHER_set_asn1_iv, + EVP_CIPHER_get_asn1_iv, + NULL +}; + +/* 3DES CBC EVP */ +const EVP_CIPHER cryptodev_3des_cbc = { + NID_des_ede3_cbc, + 8, 24, 8, + EVP_CIPH_CBC_MODE, + cryptodev_init_key, + cryptodev_cipher, + cryptodev_cleanup, + sizeof(struct dev_crypto_state), + EVP_CIPHER_set_asn1_iv, + EVP_CIPHER_get_asn1_iv, + NULL +}; + +const EVP_CIPHER cryptodev_bf_cbc = { + NID_bf_cbc, + 8, 16, 8, + EVP_CIPH_CBC_MODE, + cryptodev_init_key, + cryptodev_cipher, + cryptodev_cleanup, + sizeof(struct dev_crypto_state), + EVP_CIPHER_set_asn1_iv, + EVP_CIPHER_get_asn1_iv, + NULL +}; + +const EVP_CIPHER cryptodev_cast_cbc = { + NID_cast5_cbc, + 8, 16, 8, + EVP_CIPH_CBC_MODE, + cryptodev_init_key, + cryptodev_cipher, + cryptodev_cleanup, + sizeof(struct dev_crypto_state), + EVP_CIPHER_set_asn1_iv, + EVP_CIPHER_get_asn1_iv, + NULL +}; + +const EVP_CIPHER cryptodev_aes_cbc = { + NID_aes_128_cbc, + 16, 16, 16, + EVP_CIPH_CBC_MODE, + cryptodev_init_key, + cryptodev_cipher, + cryptodev_cleanup, + sizeof(struct dev_crypto_state), + EVP_CIPHER_set_asn1_iv, + EVP_CIPHER_get_asn1_iv, + NULL +}; + +/* + * Registered by the ENGINE when used to find out how to deal with + * a particular NID in the ENGINE. this says what we'll do at the + * top level - note, that list is restricted by what we answer with + */ +static int +cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher, + const int **nids, int nid) +{ + if (!cipher) + return (cryptodev_usable_ciphers(nids)); + + switch (nid) { + case NID_des_ede3_cbc: + *cipher = &cryptodev_3des_cbc; + break; + case NID_des_cbc: + *cipher = &cryptodev_des_cbc; + break; + case NID_bf_cbc: + *cipher = &cryptodev_bf_cbc; + break; + case NID_cast5_cbc: + *cipher = &cryptodev_cast_cbc; + break; + case NID_aes_128_cbc: + *cipher = &cryptodev_aes_cbc; + break; + default: + *cipher = NULL; + break; + } + return (*cipher != NULL); +} + +static int +cryptodev_engine_digests(ENGINE *e, const EVP_MD **digest, + const int **nids, int nid) +{ + if (!digest) + return (cryptodev_usable_digests(nids)); + + switch (nid) { + case NID_md5: + *digest = NULL; /* need to make a clean md5 critter */ + break; + default: + *digest = NULL; + break; + } + return (*digest != NULL); +} + +/* + * Convert a BIGNUM to the representation that /dev/crypto needs. + * Upon completion of use, the caller is responsible for freeing + * crp->crp_p. + */ +static int +bn2crparam(const BIGNUM *a, struct crparam *crp) +{ + int i, j, k; + ssize_t words, bytes, bits; + u_char *b; + + crp->crp_p = NULL; + crp->crp_nbits = 0; + + bits = BN_num_bits(a); + bytes = (bits + 7) / 8; + + b = malloc(bytes); + if (b == NULL) + return (1); + + crp->crp_p = b; + crp->crp_nbits = bits; + + for (i = 0, j = 0; i < a->top; i++) { + for (k = 0; k < BN_BITS2 / 8; k++) { + if ((j + k) >= bytes) + return (0); + b[j + k] = a->d[i] >> (k * 8); + } + j += BN_BITS2 / 8; + } + return (0); +} + +/* Convert a /dev/crypto parameter to a BIGNUM */ +static int +crparam2bn(struct crparam *crp, BIGNUM *a) +{ + u_int8_t *pd; + int i, bytes; + + bytes = (crp->crp_nbits + 7) / 8; + + if (bytes == 0) + return (-1); + + if ((pd = (u_int8_t *) malloc(bytes)) == NULL) + return (-1); + + for (i = 0; i < bytes; i++) + pd[i] = crp->crp_p[bytes - i - 1]; + + BN_bin2bn(pd, bytes, a); + free(pd); + + return (0); +} + +static void +zapparams(struct crypt_kop *kop) +{ + int i; + + for (i = 0; i <= kop->crk_iparams + kop->crk_oparams; i++) { + if (kop->crk_param[i].crp_p) + free(kop->crk_param[i].crp_p); + kop->crk_param[i].crp_p = NULL; + kop->crk_param[i].crp_nbits = 0; + } +} + +static int +cryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r, int slen, BIGNUM *s) +{ + int fd, ret = -1; + + if ((fd = get_asym_dev_crypto()) < 0) + return (ret); + + if (r) { + kop->crk_param[kop->crk_iparams].crp_p = calloc(rlen, sizeof(char)); + kop->crk_param[kop->crk_iparams].crp_nbits = rlen * 8; + kop->crk_oparams++; + } + if (s) { + kop->crk_param[kop->crk_iparams+1].crp_p = calloc(slen, sizeof(char)); + kop->crk_param[kop->crk_iparams+1].crp_nbits = slen * 8; + kop->crk_oparams++; + } + + if (ioctl(fd, CIOCKEY, kop) == 0) { + if (r) + crparam2bn(&kop->crk_param[kop->crk_iparams], r); + if (s) + crparam2bn(&kop->crk_param[kop->crk_iparams+1], s); + ret = 0; + } + + return (ret); +} + +static int +cryptodev_bn_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) +{ + struct crypt_kop kop; + int ret = 1; + + /* Currently, we know we can do mod exp iff we can do any + * asymmetric operations at all. + */ + if (cryptodev_asymfeat == 0) { + ret = BN_mod_exp(r, a, p, m, ctx); + return (ret); + } + + memset(&kop, 0, sizeof kop); + kop.crk_op = CRK_MOD_EXP; + + /* inputs: a^p % m */ + if (bn2crparam(a, &kop.crk_param[0])) + goto err; + if (bn2crparam(p, &kop.crk_param[1])) + goto err; + if (bn2crparam(m, &kop.crk_param[2])) + goto err; + kop.crk_iparams = 3; + + if (cryptodev_asym(&kop, BN_num_bytes(m), r, 0, NULL) == -1) { + const RSA_METHOD *meth = RSA_PKCS1_SSLeay(); + ret = meth->bn_mod_exp(r, a, p, m, ctx, in_mont); + } +err: + zapparams(&kop); + return (ret); +} + +static int +cryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) +{ + int r; + BN_CTX *ctx; + + ctx = BN_CTX_new(); + r = cryptodev_bn_mod_exp(r0, I, rsa->d, rsa->n, ctx, NULL); + BN_CTX_free(ctx); + return (r); +} + +static int +cryptodev_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) +{ + struct crypt_kop kop; + int ret = 1; + + if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) { + /* XXX 0 means failure?? */ + return (0); + } + + memset(&kop, 0, sizeof kop); + kop.crk_op = CRK_MOD_EXP_CRT; + /* inputs: rsa->p rsa->q I rsa->dmp1 rsa->dmq1 rsa->iqmp */ + if (bn2crparam(rsa->p, &kop.crk_param[0])) + goto err; + if (bn2crparam(rsa->q, &kop.crk_param[1])) + goto err; + if (bn2crparam(I, &kop.crk_param[2])) + goto err; + if (bn2crparam(rsa->dmp1, &kop.crk_param[3])) + goto err; + if (bn2crparam(rsa->dmq1, &kop.crk_param[4])) + goto err; + if (bn2crparam(rsa->iqmp, &kop.crk_param[5])) + goto err; + kop.crk_iparams = 6; + + if (cryptodev_asym(&kop, BN_num_bytes(rsa->n), r0, 0, NULL) == -1) { + const RSA_METHOD *meth = RSA_PKCS1_SSLeay(); + ret = (*meth->rsa_mod_exp)(r0, I, rsa); + } +err: + zapparams(&kop); + return (ret); +} + +static RSA_METHOD cryptodev_rsa = { + "cryptodev RSA method", + NULL, /* rsa_pub_enc */ + NULL, /* rsa_pub_dec */ + NULL, /* rsa_priv_enc */ + NULL, /* rsa_priv_dec */ + NULL, + NULL, + NULL, /* init */ + NULL, /* finish */ + 0, /* flags */ + NULL, /* app_data */ + NULL, /* rsa_sign */ + NULL /* rsa_verify */ +}; + +static int +cryptodev_dsa_bn_mod_exp(DSA *dsa, BIGNUM *r, BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) +{ + return (cryptodev_bn_mod_exp(r, a, p, m, ctx, m_ctx)); +} + +static int +cryptodev_dsa_dsa_mod_exp(DSA *dsa, BIGNUM *t1, BIGNUM *g, + BIGNUM *u1, BIGNUM *pub_key, BIGNUM *u2, BIGNUM *p, + BN_CTX *ctx, BN_MONT_CTX *mont) +{ + BIGNUM t2; + int ret = 0; + + BN_init(&t2); + + /* v = ( g^u1 * y^u2 mod p ) mod q */ + /* let t1 = g ^ u1 mod p */ + ret = 0; + + if (!dsa->meth->bn_mod_exp(dsa,t1,dsa->g,u1,dsa->p,ctx,mont)) + goto err; + + /* let t2 = y ^ u2 mod p */ + if (!dsa->meth->bn_mod_exp(dsa,&t2,dsa->pub_key,u2,dsa->p,ctx,mont)) + goto err; + /* let u1 = t1 * t2 mod p */ + if (!BN_mod_mul(u1,t1,&t2,dsa->p,ctx)) + goto err; + + BN_copy(t1,u1); + + ret = 1; +err: + BN_free(&t2); + return(ret); +} + +static DSA_SIG * +cryptodev_dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) +{ + struct crypt_kop kop; + BIGNUM *r = NULL, *s = NULL; + DSA_SIG *dsaret = NULL; + + if ((r = BN_new()) == NULL) + goto err; + if ((s = BN_new()) == NULL) { + BN_free(r); + goto err; + } + + printf("bar\n"); + memset(&kop, 0, sizeof kop); + kop.crk_op = CRK_DSA_SIGN; + + /* inputs: dgst dsa->p dsa->q dsa->g dsa->priv_key */ + kop.crk_param[0].crp_p = (caddr_t)dgst; + kop.crk_param[0].crp_nbits = dlen * 8; + if (bn2crparam(dsa->p, &kop.crk_param[1])) + goto err; + if (bn2crparam(dsa->q, &kop.crk_param[2])) + goto err; + if (bn2crparam(dsa->g, &kop.crk_param[3])) + goto err; + if (bn2crparam(dsa->priv_key, &kop.crk_param[4])) + goto err; + kop.crk_iparams = 5; + + if (cryptodev_asym(&kop, BN_num_bytes(dsa->q), r, + BN_num_bytes(dsa->q), s) == 0) { + dsaret = DSA_SIG_new(); + dsaret->r = r; + dsaret->s = s; + } else { + const DSA_METHOD *meth = DSA_OpenSSL(); + BN_free(r); + BN_free(s); + dsaret = (meth->dsa_do_sign)(dgst, dlen, dsa); + } +err: + kop.crk_param[0].crp_p = NULL; + zapparams(&kop); + return (dsaret); +} + +static int +cryptodev_dsa_verify(const unsigned char *dgst, int dlen, + DSA_SIG *sig, DSA *dsa) +{ + struct crypt_kop kop; + int dsaret = 1; + + memset(&kop, 0, sizeof kop); + kop.crk_op = CRK_DSA_VERIFY; + + /* inputs: dgst dsa->p dsa->q dsa->g dsa->pub_key sig->r sig->s */ + kop.crk_param[0].crp_p = (caddr_t)dgst; + kop.crk_param[0].crp_nbits = dlen * 8; + if (bn2crparam(dsa->p, &kop.crk_param[1])) + goto err; + if (bn2crparam(dsa->q, &kop.crk_param[2])) + goto err; + if (bn2crparam(dsa->g, &kop.crk_param[3])) + goto err; + if (bn2crparam(dsa->pub_key, &kop.crk_param[4])) + goto err; + if (bn2crparam(sig->r, &kop.crk_param[5])) + goto err; + if (bn2crparam(sig->s, &kop.crk_param[6])) + goto err; + kop.crk_iparams = 7; + + if (cryptodev_asym(&kop, 0, NULL, 0, NULL) == 0) { + dsaret = kop.crk_status; + } else { + const DSA_METHOD *meth = DSA_OpenSSL(); + + dsaret = (meth->dsa_do_verify)(dgst, dlen, sig, dsa); + } +err: + kop.crk_param[0].crp_p = NULL; + zapparams(&kop); + return (dsaret); +} + +static DSA_METHOD cryptodev_dsa = { + "cryptodev DSA method", + NULL, + NULL, /* dsa_sign_setup */ + NULL, + NULL, /* dsa_mod_exp */ + NULL, + NULL, /* init */ + NULL, /* finish */ + 0, /* flags */ + NULL /* app_data */ +}; + +static int +cryptodev_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx) +{ + return (cryptodev_bn_mod_exp(r, a, p, m, ctx, m_ctx)); +} + +static int +cryptodev_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) +{ + struct crypt_kop kop; + int dhret = 1; + int fd, keylen; + + if ((fd = get_asym_dev_crypto()) < 0) { + const DH_METHOD *meth = DH_OpenSSL(); + + return ((meth->compute_key)(key, pub_key, dh)); + } + + keylen = BN_num_bits(dh->p); + + memset(&kop, 0, sizeof kop); + kop.crk_op = CRK_DH_COMPUTE_KEY; + + /* inputs: dh->priv_key pub_key dh->p key */ + if (bn2crparam(dh->priv_key, &kop.crk_param[0])) + goto err; + if (bn2crparam(pub_key, &kop.crk_param[1])) + goto err; + if (bn2crparam(dh->p, &kop.crk_param[2])) + goto err; + kop.crk_iparams = 3; + + kop.crk_param[3].crp_p = key; + kop.crk_param[3].crp_nbits = keylen * 8; + kop.crk_oparams = 1; + + if (ioctl(fd, CIOCKEY, &kop) == -1) { + const DH_METHOD *meth = DH_OpenSSL(); + + dhret = (meth->compute_key)(key, pub_key, dh); + } +err: + kop.crk_param[3].crp_p = NULL; + zapparams(&kop); + return (dhret); +} + +static DH_METHOD cryptodev_dh = { + "cryptodev DH method", + NULL, /* cryptodev_dh_generate_key */ + NULL, + NULL, + NULL, + NULL, + 0, /* flags */ + NULL /* app_data */ +}; + +/* + * ctrl right now is just a wrapper that doesn't do much + * but I expect we'll want some options soon. + */ +static int +cryptodev_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()) +{ + struct syslog_data sd = SYSLOG_DATA_INIT; + + switch (cmd) { + default: + syslog_r(LOG_ERR, &sd, + "cryptodev_ctrl: unknown command %d", cmd); + break; + } + return (1); +} + +void +ENGINE_load_cryptodev(void) +{ + ENGINE *engine = ENGINE_new(); + int fd; + + if (engine == NULL) + return; + if ((fd = get_dev_crypto()) < 0) + return; + + /* + * find out what asymmetric crypto algorithms we support + */ + if (ioctl(fd, CIOCASYMFEAT, &cryptodev_asymfeat) == -1) { + close(fd); + return; + } + close(fd); + + if (!ENGINE_set_id(engine, "cryptodev") || + !ENGINE_set_name(engine, "OpenBSD cryptodev engine") || + !ENGINE_set_ciphers(engine, cryptodev_engine_ciphers) || + !ENGINE_set_digests(engine, cryptodev_engine_digests) || + !ENGINE_set_ctrl_function(engine, cryptodev_ctrl) || + !ENGINE_set_cmd_defns(engine, cryptodev_defns)) { + ENGINE_free(engine); + return; + } + + if (ENGINE_set_RSA(engine, &cryptodev_rsa)) { + const RSA_METHOD *rsa_meth = RSA_PKCS1_SSLeay(); + + cryptodev_rsa.bn_mod_exp = rsa_meth->bn_mod_exp; + cryptodev_rsa.rsa_mod_exp = rsa_meth->rsa_mod_exp; + cryptodev_rsa.rsa_pub_enc = rsa_meth->rsa_pub_enc; + cryptodev_rsa.rsa_pub_dec = rsa_meth->rsa_pub_dec; + cryptodev_rsa.rsa_priv_enc = rsa_meth->rsa_priv_enc; + cryptodev_rsa.rsa_priv_dec = rsa_meth->rsa_priv_dec; + if (cryptodev_asymfeat & CRF_MOD_EXP) { + cryptodev_rsa.bn_mod_exp = cryptodev_bn_mod_exp; + if (cryptodev_asymfeat & CRF_MOD_EXP_CRT) + cryptodev_rsa.rsa_mod_exp = + cryptodev_rsa_mod_exp; + else + cryptodev_rsa.rsa_mod_exp = + cryptodev_rsa_nocrt_mod_exp; + } + } + + if (ENGINE_set_DSA(engine, &cryptodev_dsa)) { + const DSA_METHOD *meth = DSA_OpenSSL(); + + memcpy(&cryptodev_dsa, meth, sizeof(DSA_METHOD)); + if (cryptodev_asymfeat & CRF_DSA_SIGN) + cryptodev_dsa.dsa_do_sign = cryptodev_dsa_do_sign; + if (cryptodev_asymfeat & CRF_MOD_EXP) { + cryptodev_dsa.bn_mod_exp = cryptodev_dsa_bn_mod_exp; + cryptodev_dsa.dsa_mod_exp = cryptodev_dsa_dsa_mod_exp; + } + if (cryptodev_asymfeat & CRF_DSA_VERIFY) + cryptodev_dsa.dsa_do_verify = cryptodev_dsa_verify; + } + + if (ENGINE_set_DH(engine, &cryptodev_dh)){ + const DH_METHOD *dh_meth = DH_OpenSSL(); + + cryptodev_dh.generate_key = dh_meth->generate_key; + cryptodev_dh.compute_key = dh_meth->compute_key; + cryptodev_dh.bn_mod_exp = dh_meth->bn_mod_exp; + if (cryptodev_asymfeat & CRF_MOD_EXP) { + cryptodev_dh.bn_mod_exp = cryptodev_mod_exp_dh; + if (cryptodev_asymfeat & CRF_DH_COMPUTE_KEY) + cryptodev_dh.compute_key = + cryptodev_dh_compute_key; + } + } + + ENGINE_add(engine); + ENGINE_free(engine); + ERR_clear_error(); +} + +#endif /* __OpenBSD__ */ diff --git a/demos/maurice/.cvsignore b/demos/maurice/.cvsignore new file mode 100644 index 000000000..a99bec344 --- /dev/null +++ b/demos/maurice/.cvsignore @@ -0,0 +1,4 @@ +example1 +example2 +example3 +example4 diff --git a/doc/crypto/ASN1_OBJECT_new.pod b/doc/crypto/ASN1_OBJECT_new.pod new file mode 100644 index 000000000..51679bfcd --- /dev/null +++ b/doc/crypto/ASN1_OBJECT_new.pod @@ -0,0 +1,43 @@ +=pod + +=head1 NAME + +ASN1_OBJECT_new, ASN1_OBJECT_free, - object allocation functions + +=head1 SYNOPSIS + + ASN1_OBJECT *ASN1_OBJECT_new(void); + void ASN1_OBJECT_free(ASN1_OBJECT *a); + +=head1 DESCRIPTION + +The ASN1_OBJECT allocation routines, allocate and free an +ASN1_OBJECT structure, which represents an ASN1 OBJECT IDENTIFIER. + +ASN1_OBJECT_new() allocates and initializes a ASN1_OBJECT structure. + +ASN1_OBJECT_free() frees up the B structure B. + +=head1 NOTES + +Although ASN1_OBJECT_new() allocates a new ASN1_OBJECT structure it +is almost never used in applications. The ASN1 object utility functions +such as OBJ_nid2obj() are used instead. + +=head1 RETURN VALUES + +If the allocation fails, ASN1_OBJECT_new() returns B and sets an error +code that can be obtained by L. +Otherwise it returns a pointer to the newly allocated structure. + +ASN1_OBJECT_free() returns no value. + +=head1 SEE ALSO + +L, L + +=head1 HISTORY + +ASN1_OBJECT_new() and ASN1_OBJECT_free() are available in all versions of SSLeay and OpenSSL. + +=cut diff --git a/doc/crypto/EVP_PKEY_new.pod b/doc/crypto/EVP_PKEY_new.pod new file mode 100644 index 000000000..10687e458 --- /dev/null +++ b/doc/crypto/EVP_PKEY_new.pod @@ -0,0 +1,47 @@ +=pod + +=head1 NAME + +EVP_PKEY_new, EVP_PKEY_free - private key allocation functions. + +=head1 SYNOPSIS + + #include + + EVP_PKEY *EVP_PKEY_new(void); + void EVP_PKEY_free(EVP_PKEY *key); + + +=head1 DESCRIPTION + +The EVP_PKEY_new() function allocates an empty B +structure which is used by OpenSSL to store private keys. + +EVP_PKEY_free() frees up the private key B. + +=head1 NOTES + +The B structure is used by various OpenSSL functions +which require a general private key without reference to any +particular algorithm. + +The structure returned by EVP_PKEY_new() is empty. To add a +private key to this empty structure the functions described in +L should be used. + +=head1 RETURN VALUES + +EVP_PKEY_new() returns either the newly allocated B +structure of B if an error occurred. + +EVP_PKEY_free() does not return a value. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +TBA + +=cut diff --git a/doc/crypto/EVP_PKEY_set1_RSA.pod b/doc/crypto/EVP_PKEY_set1_RSA.pod new file mode 100644 index 000000000..2db692e27 --- /dev/null +++ b/doc/crypto/EVP_PKEY_set1_RSA.pod @@ -0,0 +1,80 @@ +=pod + +=head1 NAME + +EVP_PKEY_set1_RSA, EVP_PKEY_set1_DSA, EVP_PKEY_set1_DH, EVP_PKEY_set1_EC_KEY, +EVP_PKEY_get1_RSA, EVP_PKEY_get1_DSA, EVP_PKEY_get1_DH, EVP_PKEY_get1_EC_KEY, +EVP_PKEY_assign_RSA, EVP_PKEY_assign_DSA, EVP_PKEY_assign_DH, EVP_PKEY_assign_EC_KEY, +EVP_PKEY_type - EVP_PKEY assignment functions. + +=head1 SYNOPSIS + + #include + + int EVP_PKEY_set1_RSA(EVP_PKEY *pkey,RSA *key); + int EVP_PKEY_set1_DSA(EVP_PKEY *pkey,DSA *key); + int EVP_PKEY_set1_DH(EVP_PKEY *pkey,DH *key); + int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey,EC_KEY *key); + + RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey); + DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey); + DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey); + EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey); + + int EVP_PKEY_assign_RSA(EVP_PKEY *pkey,RSA *key); + int EVP_PKEY_assign_DSA(EVP_PKEY *pkey,DSA *key); + int EVP_PKEY_assign_DH(EVP_PKEY *pkey,DH *key); + int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey,EC_KEY *key); + + int EVP_PKEY_type(int type); + +=head1 DESCRIPTION + +EVP_PKEY_set1_RSA(), EVP_PKEY_set1_DSA(), EVP_PKEY_set1_DH() and +EVP_PKEY_set1_EC_KEY() set the key referenced by B to B. + +EVP_PKEY_get1_RSA(), EVP_PKEY_get1_DSA(), EVP_PKEY_get1_DH() and +EVP_PKEY_get1_EC_KEY() return the referenced key in B or +B if the key is not of the correct type. + +EVP_PKEY_assign_RSA() EVP_PKEY_assign_DSA(), EVP_PKEY_assign_DH() +and EVP_PKEY_assign_EC_KEY() also set the referenced key to B +however these use the supplied B internally and so B +will be freed when the parent B is freed. + +EVP_PKEY_type() returns the type of key corresponding to the value +B. The type of a key can be obtained with +EVP_PKEY_type(pkey->type). The return value will be EVP_PKEY_RSA, +EVP_PKEY_DSA, EVP_PKEY_DH or EVP_PKEY_EC for the corresponding +key types or NID_undef if the key type is unassigned. + +=head1 NOTES + +In accordance with the OpenSSL naming convention the key obtained +from or assigned to the B using the B<1> functions must be +freed as well as B. + +EVP_PKEY_assign_RSA() EVP_PKEY_assign_DSA(), EVP_PKEY_assign_DH() +EVP_PKEY_assign_EC_KEY() are implemented as macros. + +=head1 RETURN VALUES + +EVP_PKEY_set1_RSA(), EVP_PKEY_set1_DSA(), EVP_PKEY_set1_DH() and +EVP_PKEY_set1_EC_KEY() return 1 for success or 0 for failure. + +EVP_PKEY_get1_RSA(), EVP_PKEY_get1_DSA(), EVP_PKEY_get1_DH() and +EVP_PKEY_get1_EC_KEY() return the referenced key or B if +an error occurred. + +EVP_PKEY_assign_RSA() EVP_PKEY_assign_DSA(), EVP_PKEY_assign_DH() +and EVP_PKEY_assign_EC_KEY() return 1 for success and 0 for failure. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +TBA + +=cut diff --git a/doc/crypto/OBJ_nid2obj.pod b/doc/crypto/OBJ_nid2obj.pod new file mode 100644 index 000000000..50650bdbc --- /dev/null +++ b/doc/crypto/OBJ_nid2obj.pod @@ -0,0 +1,149 @@ +=pod + +=head1 NAME + +OBJ_nid2obj, OBJ_nid2ln, OBJ_nid2sn, OBJ_obj2nid, OBJ_txt2nid, OBJ_ln2nid, OBJ_sn2nid, +OBJ_cmp, OBJ_dup, OBJ_txt2obj, OBJ_obj2txt, OBJ_create, OBJ_cleanup - ASN1 object utility +functions + +=head1 SYNOPSIS + + ASN1_OBJECT * OBJ_nid2obj(int n); + const char * OBJ_nid2ln(int n); + const char * OBJ_nid2sn(int n); + + int OBJ_obj2nid(const ASN1_OBJECT *o); + int OBJ_ln2nid(const char *ln); + int OBJ_sn2nid(const char *sn); + + int OBJ_txt2nid(const char *s); + + ASN1_OBJECT * OBJ_txt2obj(const char *s, int no_name); + int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name); + + int OBJ_cmp(const ASN1_OBJECT *a,const ASN1_OBJECT *b); + ASN1_OBJECT * OBJ_dup(const ASN1_OBJECT *o); + + int OBJ_create(const char *oid,const char *sn,const char *ln); + void OBJ_cleanup(void); + +=head1 DESCRIPTION + +The ASN1 object utility functions process ASN1_OBJECT structures which are +a representation of the ASN1 OBJECT IDENTIFIER (OID) type. + +OBJ_nid2obj(), OBJ_nid2ln() and OBJ_nid2sn() convert the NID B to +an ASN1_OBJECT structure, its long name and its short name respectively, +or B is an error occurred. + +OBJ_obj2nid(), OBJ_ln2nid(), OBJ_sn2nid() return the corresponding NID +for the object B, the long name or the short name respectively +or NID_undef if an error occurred. + +OBJ_txt2nid() returns NID corresponding to text string . B can be +a long name, a short name or the numerical respresentation of an object. + +OBJ_txt2obj() converts the text string B into an ASN1_OBJECT structure. +If B is 0 then long names and short names will be interpreted +as well as numerical forms. If B is 1 only the numerical form +is acceptable. + +OBJ_obj2txt() converts the B B into a textual representation. +The representation is written as a null terminated string to B +at most B bytes are written, truncating the result if necessary. +The total amount of space required is returned. If B is 0 then +if the object has a long or short name then that will be used, otherwise +the numerical form will be used. If B is 1 then the numerical +form will always be used. + +OBJ_cmp() compares B to B. If the two are identical 0 is returned. + +OBJ_dup() returns a copy of B. + +OBJ_create() adds a new object to the internal table. B is the +numerical form of the object, B the short name and B the +long name. A new NID is returned for the created object. + +OBJ_cleanup() cleans up OpenSSLs internal object table: this should +be called before an application exits if any new objects were added +using OBJ_create(). + +=head1 NOTES + +Objects in OpenSSL can have a short name, a long name and a numerical +identifier (NID) associated with them. A standard set of objects is +represented in an internal table. The appropriate values are defined +in the header file B. + +For example the OID for commonName has the following definitions: + + #define SN_commonName "CN" + #define LN_commonName "commonName" + #define NID_commonName 13 + +New objects can be added by calling OBJ_create(). + +Table objects have certain advantages over other objects: for example +their NIDs can be used in a C language switch statement. They are +also static constant structures which are shared: that is there +is only a single constant structure for each table object. + +Objects which are not in the table have the NID value NID_undef. + +Objects do not need to be in the internal tables to be processed, +the functions OBJ_txt2obj() and OBJ_obj2txt() can process the numerical +form of an OID. + +=head1 EXAMPLES + +Create an object for B: + + ASN1_OBJECT *o; + o = OBJ_nid2obj(NID_commonName); + +Check is an object is B + + if (OBJ_obj2nid(obj) == NID_commonName) + /* Do something */ + +Create a new NID and initialize an object from it: + + int new_nid; + ASN1_OBJECT *obj; + new_nid = OBJ_create("1.2.3.4", "NewOID", "New Object Identifier"); + + obj = OBJ_nid2obj(new_nid); + +Create a new object directly: + + obj = OBJ_txt2obj("1.2.3.4", 1); + +=head1 BUGS + +OBJ_obj2txt() is awkward and messy to use: it doesn't follow the +convention of other OpenSSL functions where the buffer can be set +to B to determine the amount of data that should be written. +Instead B must point to a valid buffer and B should +be set to a positive value. A buffer length of 80 should be more +than enough to handle any OID encountered in practice. + +=head1 RETURN VALUES + +OBJ_nid2obj() returns an ASN1_OBJECT structure or B is an +error occurred. + +OBJ_nid2ln() and OBJ_nid2sn() returns a valid string or B +on error. + +OBJ_obj2nid(), OBJ_ln2nid(), OBJ_sn2nid() and OBJ_txt2nid() return +a NID or NID_undef on error. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +TBA + +=cut diff --git a/doc/crypto/PKCS12_parse.pod b/doc/crypto/PKCS12_parse.pod new file mode 100644 index 000000000..51344f883 --- /dev/null +++ b/doc/crypto/PKCS12_parse.pod @@ -0,0 +1,50 @@ +=pod + +=head1 NAME + +PKCS12_parse - parse a PKCS#12 structure + +=head1 SYNOPSIS + + #include + +int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca); + +=head1 DESCRIPTION + +PKCS12_parse() parses a PKCS12 structure. + +B is the B structure to parse. B is the passphrase to use. +If successful the private key will be written to B<*pkey>, the corresponding +certificate to B<*cert> and any additional certificates to B<*ca>. + +=head1 NOTES + +The parameters B and B cannot be B. B can be +in which case additional certificates will be discarded. B<*ca> can also +be a valid STACK in which case additional certificates are appended to +B<*ca>. If B<*ca> is B a new STACK will be allocated. + +The B and B attributes (if present) on each certificate +will be stored in the B and B attributes of the B structure. + +=head1 BUGS + +Only a single private key and corresponding certificate is returned by this function. +More complex PKCS#12 files with multiple private keys will only return the first +match. + +Only B and B attributes are currently stored in certificates. +Other attributes are discarded. + +Attributes currently cannot be store in the private key B structure. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +PKCS12_parse was added in OpenSSL 0.9.3 + +=cut diff --git a/doc/crypto/PKCS7_decrypt.pod b/doc/crypto/PKCS7_decrypt.pod new file mode 100644 index 000000000..b0ca067b8 --- /dev/null +++ b/doc/crypto/PKCS7_decrypt.pod @@ -0,0 +1,53 @@ +=pod + +=head1 NAME + +PKCS7_decrypt - decrypt content from a PKCS#7 envelopedData structure + +=head1 SYNOPSIS + +int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags); + +=head1 DESCRIPTION + +PKCS7_decrypt() extracts and decrypts the content from a PKCS#7 envelopedData +structure. B is the private key of the recipient, B is the +recipients certificate, B is a BIO to write the content to and +B is an optional set of flags. + +=head1 NOTES + +OpenSSL_add_all_algorithms() (or equivalent) should be called before using this +function or errors about unknown algorithms will occur. + +Although the recipients certificate is not needed to decrypt the data it is needed +to locate the appropriate (of possible several) recipients in the PKCS#7 structure. + +The following flags can be passed in the B parameter. + +If the B flag is set MIME headers for type B are deleted +from the content. If the content is not of type B then an error is +returned. + +=head1 RETURN VALUES + +PKCS7_decrypt() returns either 1 for success or 0 for failure. +The error can be obtained from ERR_get_error(3) + +=head1 BUGS + +PKCS7_decrypt() must be passed the correct recipient key and certificate. It would +be better if it could look up the correct key and certificate from a database. + +The lack of single pass processing and need to hold all data in memory as +mentioned in PKCS7_sign() also applies to PKCS7_verify(). + +=head1 SEE ALSO + +L, L + +=head1 HISTORY + +PKCS7_decrypt() was added to OpenSSL 0.9.5 + +=cut diff --git a/doc/crypto/PKCS7_encrypt.pod b/doc/crypto/PKCS7_encrypt.pod new file mode 100644 index 000000000..1a507b22a --- /dev/null +++ b/doc/crypto/PKCS7_encrypt.pod @@ -0,0 +1,65 @@ +=pod + +=head1 NAME + +PKCS7_encrypt - create a PKCS#7 envelopedData structure + +=head1 SYNOPSIS + +PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, int flags); + +=head1 DESCRIPTION + +PKCS7_encrypt() creates and returns a PKCS#7 envelopedData structure. B +is a list of recipient certificates. B is the content to be encrypted. +B is the symmetric cipher to use. B is an optional set of flags. + +=head1 NOTES + +Only RSA keys are supported in PKCS#7 and envelopedData so the recipient certificates +supplied to this function must all contain RSA public keys, though they do not have to +be signed using the RSA algorithm. + +EVP_des_ede3_cbc() (triple DES) is the algorithm of choice for S/MIME use because +most clients will support it. + +Some old "export grade" clients may only support weak encryption using 40 or 64 bit +RC2. These can be used by passing EVP_rc2_40_cbc() and EVP_rc2_64_cbc() respectively. + +The algorithm passed in the B parameter must support ASN1 encoding of its +parameters. + +Many browsers implement a "sign and encrypt" option which is simply an S/MIME +envelopedData containing an S/MIME signed message. This can be readily produced +by storing the S/MIME signed message in a memory BIO and passing it to +PKCS7_encrypt(). + +The following flags can be passed in the B parameter. + +If the B flag is set MIME headers for type B are prepended +to the data. + +Normally the supplied content is translated into MIME canonical format (as required +by the S/MIME specifications) if B is set no translation occurs. This +option should be used if the supplied data is in binary format otherwise the translation +will corrupt it. If B is set then B is ignored. + +=head1 RETURN VALUES + +PKCS7_encrypt() returns either a valid PKCS7 structure or NULL if an error occurred. +The error can be obtained from ERR_get_error(3). + +=head1 BUGS + +The lack of single pass processing and need to hold all data in memory as +mentioned in PKCS7_sign() also applies to PKCS7_verify(). + +=head1 SEE ALSO + +L, L + +=head1 HISTORY + +PKCS7_decrypt() was added to OpenSSL 0.9.5 + +=cut diff --git a/doc/crypto/PKCS7_sign.pod b/doc/crypto/PKCS7_sign.pod new file mode 100644 index 000000000..fc7e649b3 --- /dev/null +++ b/doc/crypto/PKCS7_sign.pod @@ -0,0 +1,85 @@ +=pod + +=head1 NAME + +PKCS7_sign - create a PKCS#7 signedData structure + +=head1 SYNOPSIS + +PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, BIO *data, int flags); + +=head1 DESCRIPTION + +PKCS7_sign() creates and returns a PKCS#7 signedData structure. B +is the certificate to sign with, B is the corresponsding private key. +B is an optional additional set of certificates to include in the +PKCS#7 structure (for example any intermediate CAs in the chain). + +The data to be signed is read from BIO B. + +B is an optional set of flags. + +=head1 NOTES + +Any of the following flags (ored together) can be passed in the B parameter. + +Many S/MIME clients expect the signed content to include valid MIME headers. If +the B flag is set MIME headers for type B are prepended +to the data. + +If B is set the signer's certificate will not be included in the +PKCS7 structure, the signer's certificate must still be supplied in the B +parameter though. This can reduce the size of the signature if the signers certificate +can be obtained by other means: for example a previously signed message. + +The data being signed is included in the PKCS7 structure, unless B +is set in which case it is omitted. This is used for PKCS7 detached signatures +which are used in S/MIME plaintext signed messages for example. + +Normally the supplied content is translated into MIME canonical format (as required +by the S/MIME specifications) if B is set no translation occurs. This +option should be used if the supplied data is in binary format otherwise the translation +will corrupt it. + +The signedData structure includes several PKCS#7 autenticatedAttributes including +the signing time, the PKCS#7 content type and the supported list of ciphers in +an SMIMECapabilities attribute. If B is set then no authenticatedAttributes +will be used. If B is set then just the SMIMECapabilities are +omitted. + +If present the SMIMECapabilities attribute indicates support for the following +algorithms: triple DES, 128 bit RC2, 64 bit RC2, DES and 40 bit RC2. If any +of these algorithms is disabled then it will not be included. + +=head1 BUGS + +PKCS7_sign() is somewhat limited. It does not support multiple signers, some +advanced attributes such as counter signatures are not supported. + +The SHA1 digest algorithm is currently always used. + +When the signed data is not detached it will be stored in memory within the +B structure. This effectively limits the size of messages which can be +signed due to memory restraints. There should be a way to sign data without +having to hold it all in memory, this would however require fairly major +revisions of the OpenSSL ASN1 code. + +Clear text signing does not store the content in memory but the way PKCS7_sign() +operates means that two passes of the data must typically be made: one to compute +the signatures and a second to output the data along with the signature. There +should be a way to process the data with only a single pass. + +=head1 RETURN VALUES + +PKCS7_sign() returns either a valid PKCS7 structure or NULL if an error occurred. +The error can be obtained from ERR_get_error(3). + +=head1 SEE ALSO + +L, L + +=head1 HISTORY + +PKCS7_sign() was added to OpenSSL 0.9.5 + +=cut diff --git a/doc/crypto/PKCS7_verify.pod b/doc/crypto/PKCS7_verify.pod new file mode 100644 index 000000000..07c9fdad4 --- /dev/null +++ b/doc/crypto/PKCS7_verify.pod @@ -0,0 +1,116 @@ +=pod + +=head1 NAME + +PKCS7_verify - verify a PKCS#7 signedData structure + +=head1 SYNOPSIS + +int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, BIO *indata, BIO *out, int flags); + +int PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags); + +=head1 DESCRIPTION + +PKCS7_verify() verifies a PKCS#7 signedData structure. B is the PKCS7 +structure to verify. B is a set of certificates in which to search for +the signer's certificate. B is a trusted certficate store (used for +chain verification). B is the signed data if the content is not +present in B (that is it is detached). The content is written to B +if it is not NULL. + +B is an optional set of flags, which can be used to modify the verify +operation. + +PKCS7_get0_signers() retrieves the signer's certificates from B, it does +B check their validity or whether any signatures are valid. The B +and B parameters have the same meanings as in PKCS7_verify(). + +=head1 VERIFY PROCESS + +Normally the verify process proceeds as follows. + +Initially some sanity checks are performed on B. The type of B must +be signedData. There must be at least one signature on the data and if +the content is detached B cannot be B. + +An attempt is made to locate all the signer's certificates, first looking in +the B parameter (if it is not B) and then looking in any certificates +contained in the B structure itself. If any signer's certificates cannot be +located the operation fails. + +Each signer's certificate is chain verified using the B purpose and +the supplied trusted certificate store. Any internal certificates in the message +are used as untrusted CAs. If any chain verify fails an error code is returned. + +Finally the signed content is read (and written to B is it is not NULL) and +the signature's checked. + +If all signature's verify correctly then the function is successful. + +Any of the following flags (ored together) can be passed in the B parameter +to change the default verify behaviour. Only the flag B is +meaningful to PKCS7_get0_signers(). + +If B is set the certificates in the message itself are not +searched when locating the signer's certificate. This means that all the signers +certificates must be in the B parameter. + +If the B flag is set MIME headers for type B are deleted +from the content. If the content is not of type B then an error is +returned. + +If B is set the signer's certificates are not chain verified. + +If B is set then the certificates contained in the message are +not used as untrusted CAs. This means that the whole verify chain (apart from +the signer's certificate) must be contained in the trusted store. + +If B is set then the signatures on the data are not checked. + +=head1 NOTES + +One application of B is to only accept messages signed by +a small number of certificates. The acceptable certificates would be passed +in the B parameter. In this case if the signer is not one of the +certificates supplied in B then the verify will fail because the +signer cannot be found. + +Care should be taken when modifying the default verify behaviour, for example +setting B will totally disable all verification +and any signed message will be considered valid. This combination is however +useful if one merely wishes to write the content to B and its validity +is not considered important. + +Chain verification should arguably be performed using the signing time rather +than the current time. However since the signing time is supplied by the +signer it cannot be trusted without additional evidence (such as a trusted +timestamp). + +=head1 RETURN VALUES + +PKCS7_verify() returns 1 for a successful verification and zero or a negative +value if an error occurs. + +PKCS7_get0_signers() returns all signers or B if an error occurred. + +The error can be obtained from L + +=head1 BUGS + +The trusted certificate store is not searched for the signers certificate, +this is primarily due to the inadequacies of the current B +functionality. + +The lack of single pass processing and need to hold all data in memory as +mentioned in PKCS7_sign() also applies to PKCS7_verify(). + +=head1 SEE ALSO + +L, L + +=head1 HISTORY + +PKCS7_verify() was added to OpenSSL 0.9.5 + +=cut diff --git a/doc/crypto/SMIME_read_PKCS7.pod b/doc/crypto/SMIME_read_PKCS7.pod new file mode 100644 index 000000000..ffafa3788 --- /dev/null +++ b/doc/crypto/SMIME_read_PKCS7.pod @@ -0,0 +1,71 @@ +=pod + +=head1 NAME + +SMIME_read_PKCS7 - parse S/MIME message. + +=head1 SYNOPSIS + +PKCS7 *SMIME_read_PKCS7(BIO *in, BIO **bcont); + +=head1 DESCRIPTION + +SMIME_read_PKCS7() parses a message in S/MIME format. + +B is a BIO to read the message from. + +If cleartext signing is used then the content is saved in +a memory bio which is written to B<*bcont>, otherwise +B<*bcont> is set to B. + +The parsed PKCS#7 structure is returned or B if an +error occurred. + +=head1 NOTES + +If B<*bcont> is not B then the message is clear text +signed. B<*bcont> can then be passed to PKCS7_verify() with +the B flag set. + +Otherwise the type of the returned structure can be determined +using PKCS7_type(). + +To support future functionality if B is not B +B<*bcont> should be initialized to B. For example: + + BIO *cont = NULL; + PKCS7 *p7; + + p7 = SMIME_read_PKCS7(in, &cont); + +=head1 BUGS + +The MIME parser used by SMIME_read_PKCS7() is somewhat primitive. +While it will handle most S/MIME messages more complex compound +formats may not work. + +The parser assumes that the PKCS7 structure is always base64 +encoded and will not handle the case where it is in binary format +or uses quoted printable format. + +The use of a memory BIO to hold the signed content limits the size +of message which can be processed due to memory restraints: a +streaming single pass option should be available. + +=head1 RETURN VALUES + +SMIME_read_PKCS7() returns a valid B structure or B +is an error occurred. The error can be obtained from ERR_get_error(3). + +=head1 SEE ALSO + +L, L +L, L, +L, L +L + +=head1 HISTORY + +SMIME_read_PKCS7() was added to OpenSSL 0.9.5 + +=cut diff --git a/doc/crypto/SMIME_write_PKCS7.pod b/doc/crypto/SMIME_write_PKCS7.pod new file mode 100644 index 000000000..8093241ea --- /dev/null +++ b/doc/crypto/SMIME_write_PKCS7.pod @@ -0,0 +1,59 @@ +=pod + +=head1 NAME + +SMIME_write_PKCS7 - convert PKCS#7 structure to S/MIME format. + +=head1 SYNOPSIS + +int SMIME_write_PKCS7(BIO *out, PKCS7 *p7, BIO *data, int flags); + +=head1 DESCRIPTION + +SMIME_write_PKCS7() adds the appropriate MIME headers to a PKCS#7 +structure to produce an S/MIME message. + +B is the BIO to write the data to. B is the appropriate +B structure. If cleartext signing (B +argument. B is an optional set of flags. + +=head1 NOTES + +The following flags can be passed in the B parameter. + +If B is set then cleartext signing will be used, +this option only makes sense for signedData where B +is also set when PKCS7_sign() is also called. + +If the B flag is set MIME headers for type B +are added to the content, this only makes sense if B +is also set. + +If cleartext signing is being used then the data must be read twice: +once to compute the signature in PKCS7_sign() and once to output the +S/MIME message. + +=head1 BUGS + +SMIME_write_PKCS7() always base64 encodes PKCS#7 structures, there +should be an option to disable this. + +There should really be a way to produce cleartext signing using only +a single pass of the data. + +=head1 RETURN VALUES + +SMIME_write_PKCS7() returns 1 for success or 0 for failure. + +=head1 SEE ALSO + +L, L, +L, L +L + +=head1 HISTORY + +SMIME_write_PKCS7() was added to OpenSSL 0.9.5 + +=cut diff --git a/doc/crypto/X509_new.pod b/doc/crypto/X509_new.pod new file mode 100644 index 000000000..6de81e3d1 --- /dev/null +++ b/doc/crypto/X509_new.pod @@ -0,0 +1,37 @@ +=pod + +=head1 NAME + +X509_new, X509_free, - X509 certificate ASN1 allocation functions + +=head1 SYNOPSIS + + X509 *X509_new(void); + void X509_free(X509 *a); + +=head1 DESCRIPTION + +The X509 ASN1 allocation routines, allocate and free an +X509 structure, which represents an X509 certificate. + +X509_new() allocates and initializes a X509 structure. + +X509_free() frees up the B structure B. + +=head1 RETURN VALUES + +If the allocation fails, X509_new() returns B and sets an error +code that can be obtained by L. +Otherwise it returns a pointer to the newly allocated structure. + +X509_free() returns no value. + +=head1 SEE ALSO + +L, L + +=head1 HISTORY + +X509_new() and X509_free() are available in all versions of SSLeay and OpenSSL. + +=cut diff --git a/doc/crypto/d2i_ASN1_OBJECT.pod b/doc/crypto/d2i_ASN1_OBJECT.pod new file mode 100644 index 000000000..45bb18492 --- /dev/null +++ b/doc/crypto/d2i_ASN1_OBJECT.pod @@ -0,0 +1,29 @@ +=pod + +=head1 NAME + +d2i_ASN1_OBJECT, i2d_ASN1_OBJECT - ASN1 OBJECT IDENTIFIER functions + +=head1 SYNOPSIS + + #include + + ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a, unsigned char **pp, long length); + int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp); + +=head1 DESCRIPTION + +These functions decode and encode an ASN1 OBJECT IDENTIFIER. + +Othewise these behave in a similar way to d2i_X509() and i2d_X509() +described in the L manual page. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +TBA + +=cut diff --git a/doc/crypto/d2i_DSAPublicKey.pod b/doc/crypto/d2i_DSAPublicKey.pod new file mode 100644 index 000000000..6ebd30427 --- /dev/null +++ b/doc/crypto/d2i_DSAPublicKey.pod @@ -0,0 +1,82 @@ +=pod + +=head1 NAME + +d2i_DSAPublicKey, i2d_DSAPublicKey, d2i_DSAPrivateKey, i2d_DSAPrivateKey, +d2i_DSA_PUBKEY, i2d_DSA_PUBKEY, d2i_DSA_SIG, i2d_DSA_SIG - DSA key encoding +and parsing functions. + +=head1 SYNOPSIS + + #include + + DSA * d2i_DSAPublicKey(DSA **a, const unsigned char **pp, long length); + + int i2d_DSAPublicKey(const DSA *a, unsigned char **pp); + + DSA * d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length); + + int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp); + + DSA * d2i_DSAPrivateKey(DSA **a, const unsigned char **pp, long length); + + int i2d_DSAPrivateKey(const DSA *a, unsigned char **pp); + + DSA * d2i_DSAparams(DSA **a, const unsigned char **pp, long length); + + int i2d_DSAparams(const DSA *a, unsigned char **pp); + + DSA * d2i_DSA_SIG(DSA_SIG **a, const unsigned char **pp, long length); + + int i2d_DSA_SIG(const DSA_SIG *a, unsigned char **pp); + +=head1 DESCRIPTION + +d2i_DSAPublicKey() and i2d_DSAPublicKey() decode and encode the DSA public key +components structure. + +d2i_DSA_PUKEY() and i2d_DSA_PUKEY() decode and encode an DSA public key using a +SubjectPublicKeyInfo (certificate public key) structure. + +d2i_DSAPrivateKey(), i2d_DSAPrivateKey() decode and encode the DSA private key +components. + +d2i_DSAparams(), i2d_DSAparams() decode and encode the DSA parameters using +a B structure as defined in RFC2459. + +d2i_DSA_SIG(), i2d_DSA_SIG() decode and encode a DSA signature using a +B structure as defined in RFC2459. + +The usage of all of these functions is similar to the d2i_X509() and +i2d_X509() described in the L manual page. + +=head1 NOTES + +The B structure passed to the private key encoding functions should have +all the private key components present. + +The data encoded by the private key functions is unencrypted and therefore +offers no private key security. + +The B functions should be used in preference to the B +functions when encoding public keys because they use a standard format. + +The B functions use an non standard format the actual data encoded +depends on the value of the B field of the B key parameter. +If B is zero then only the B field is encoded as an +B. If B is 1 then a B consisting of the +B

, B, B and B respectively fields are encoded. + +The B functions also use a non standard structure consiting +consisting of a SEQUENCE containing the B

, B, B and B and +B fields respectively. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +TBA + +=cut diff --git a/doc/crypto/d2i_PKCS8PrivateKey.pod b/doc/crypto/d2i_PKCS8PrivateKey.pod new file mode 100644 index 000000000..a54b77908 --- /dev/null +++ b/doc/crypto/d2i_PKCS8PrivateKey.pod @@ -0,0 +1,56 @@ +=pod + +=head1 NAME + +d2i_PKCS8PrivateKey_bio, d2i_PKCS8PrivateKey_fp, +i2d_PKCS8PrivateKey_bio, i2d_PKCS8PrivateKey_fp, +i2d_PKCS8PrivateKey_nid_bio, i2d_PKCS8PrivateKey_nid_fp - PKCS#8 format private key functions + +=head1 SYNOPSIS + + #include + + EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u); + EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u); + + int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); + + int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); + + int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); + + int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); + +=head1 DESCRIPTION + +The PKCS#8 functions encode and decode private keys in PKCS#8 format using both +PKCS#5 v1.5 and PKCS#5 v2.0 password based encryption algorithms. + +Other than the use of DER as opposed to PEM these functions are identical to the +corresponding B function as described in the L manual page. + +=head1 NOTES + +Before using these functions L +should be called to initialize the internal algorithm lookup tables otherwise errors about +unknown algorithms will occur if an attempt is made to decrypt a private key. + +These functions are currently the only way to store encrypted private keys using DER format. + +Currently all the functions use BIOs or FILE pointers, there are no functions which +work directly on memory: this can be readily worked around by converting the buffers +to memory BIOs, see L for details. + +=head1 SEE ALSO + +L + +=cut diff --git a/doc/crypto/d2i_X509.pod b/doc/crypto/d2i_X509.pod new file mode 100644 index 000000000..fc837f02b --- /dev/null +++ b/doc/crypto/d2i_X509.pod @@ -0,0 +1,226 @@ +=pod + +=head1 NAME + +d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio, +i2d_X509_fp - X509 encode and decode functions + +=head1 SYNOPSIS + + #include + + X509 *d2i_X509(X509 **px, unsigned char **in, int len); + int i2d_X509(X509 *x, unsigned char **out); + + X509 *d2i_X509_bio(BIO *bp, X509 **x); + X509 *d2i_X509_fp(FILE *fp, X509 **x); + + int i2d_X509_bio(X509 *x, BIO *bp); + int i2d_X509_fp(X509 *x, FILE *fp); + +=head1 DESCRIPTION + +The X509 encode and decode routines encode and parse an +B structure, which represents an X509 certificate. + +d2i_X509() attempts to decode B bytes at B<*out>. If +successful a pointer to the B structure is returned. If an error +occurred then B is returned. If B is not B then the +returned structure is written to B<*px>. If B<*px> is not B +then it is assumed that B<*px> contains a valid B +structure and an attempt is made to reuse it. If the call is +successful B<*out> is incremented to the byte following the +parsed data. + +i2d_X509() encodes the structure pointed to by B into DER format. +If B is not B is writes the DER encoded data to the buffer +at B<*out>, and increments it to point after the data just written. +If the return value is negative an error occurred, otherwise it +returns the length of the encoded data. + +For OpenSSL 0.9.7 and later if B<*out> is B memory will be +allocated for a buffer and the encoded data written to it. In this +case B<*out> is not incremented and it points to the start of the +data just written. + +d2i_X509_bio() is similar to d2i_X509() except it attempts +to parse data from BIO B. + +d2i_X509_fp() is similar to d2i_X509() except it attempts +to parse data from FILE pointer B. + +i2d_X509_bio() is similar to i2d_X509() except it writes +the encoding of the structure B to BIO B. + +i2d_X509_fp() is similar to i2d_X509() except it writes +the encoding of the structure B to BIO B. + +=head1 NOTES + +The letters B and B in for example B stand for +"internal" (that is an internal C structure) and "DER". So that +B converts from internal to DER. + +The functions can also understand B forms. + +The actual X509 structure passed to i2d_X509() must be a valid +populated B structure it can B simply be fed with an +empty structure such as that returned by X509_new(). + +The encoded data is in binary form and may contain embedded zeroes. +Therefore any FILE pointers or BIOs should be opened in binary mode. +Functions such as B will B return the correct length +of the encoded structure. + +The ways that B<*in> and B<*out> are incremented after the operation +can trap the unwary. See the B section for some common +errors. + +The reason for the auto increment behaviour is to reflect a typical +usage of ASN1 functions: after one structure is encoded or decoded +another will processed after it. + +=head1 EXAMPLES + +Allocate and encode the DER encoding of an X509 structure: + + int len; + unsigned char *buf, *p; + + len = i2d_X509(x, NULL); + + buf = OPENSSL_malloc(len); + + if (buf == NULL) + /* error */ + + p = buf; + + i2d_X509(x, &p); + +If you are using OpenSSL 0.9.7 or later then this can be +simplified to: + + + int len; + unsigned char *buf; + + buf = NULL; + + len = i2d_X509(x, &buf); + + if (len < 0) + /* error */ + +Attempt to decode a buffer: + + X509 *x; + + unsigned char *buf, *p; + + int len; + + /* Something to setup buf and len */ + + p = buf; + + x = d2i_X509(NULL, &p, len); + + if (x == NULL) + /* Some error */ + +Alternative technique: + + X509 *x; + + unsigned char *buf, *p; + + int len; + + /* Something to setup buf and len */ + + p = buf; + + x = NULL; + + if(!d2i_X509(&x, &p, len)) + /* Some error */ + + +=head1 WARNINGS + +The use of temporary variable is mandatory. A common +mistake is to attempt to use a buffer directly as follows: + + int len; + unsigned char *buf; + + len = i2d_X509(x, NULL); + + buf = OPENSSL_malloc(len); + + if (buf == NULL) + /* error */ + + i2d_X509(x, &buf); + + /* Other stuff ... */ + + OPENSSL_free(buf); + +This code will result in B apparently containing garbage because +it was incremented after the call to point after the data just written. +Also B will no longer contain the pointer allocated by B +and the subsequent call to B may well crash. + +The auto allocation feature (setting buf to NULL) only works on OpenSSL +0.9.7 and later. Attempts to use it on earlier versions will typically +cause a segmentation violation. + +Another trap to avoid is misuse of the B argument to B: + + X509 *x; + + if (!d2i_X509(&x, &p, len)) + /* Some error */ + +This will probably crash somewhere in B. The reason for this +is that the variable B is uninitialized and an attempt will be made to +interpret its (invalid) value as an B structure, typically causing +a segmentation violation. If B is set to NULL first then this will not +happen. + +=head1 BUGS + +In some versions of OpenSSL the "reuse" behaviour of d2i_X509() when +B<*px> is valid is broken and some parts of the reused structure may +persist if they are not present in the new one. As a result the use +of this "reuse" behaviour is strongly discouraged. + +i2d_X509() will not return an error in many versions of OpenSSL, +if mandatory fields are not initialized due to a programming error +then the encoded structure may contain invalid data or omit the +fields entirely and will not be parsed by d2i_X509(). This may be +fixed in future so code should not assume that i2d_X509() will +always succeed. + +=head1 RETURN VALUES + +d2i_X509(), d2i_X509_bio() and d2i_X509_fp() return a valid B structure +or B if an error occurs. The error code that can be obtained by +L. + +i2d_X509(), i2d_X509_bio() and i2d_X509_fp() return a the number of bytes +successfully encoded or a negative value if an error occurs. The error code +can be obtained by L. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +d2i_X509, i2d_X509, d2i_X509_bio, d2i_X509_fp, i2d_X509_bio and i2d_X509_fp +are available in all versions of SSLeay and OpenSSL. + +=cut diff --git a/doc/crypto/d2i_X509_ALGOR.pod b/doc/crypto/d2i_X509_ALGOR.pod new file mode 100644 index 000000000..9e5cd92ca --- /dev/null +++ b/doc/crypto/d2i_X509_ALGOR.pod @@ -0,0 +1,30 @@ +=pod + +=head1 NAME + +d2i_X509_ALGOR, i2d_X509_ALGOR - AlgorithmIdentifier functions. + +=head1 SYNOPSIS + + #include + + X509_ALGOR *d2i_X509_ALGOR(X509_ALGOR **a, unsigned char **pp, long length); + int i2d_X509_ALGOR(X509_ALGOR *a, unsigned char **pp); + +=head1 DESCRIPTION + +These functions decode and encode an B structure which is +equivalent to the B structure. + +Othewise these behave in a similar way to d2i_X509() and i2d_X509() +described in the L manual page. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +TBA + +=cut diff --git a/doc/crypto/d2i_X509_CRL.pod b/doc/crypto/d2i_X509_CRL.pod new file mode 100644 index 000000000..06c5b23c0 --- /dev/null +++ b/doc/crypto/d2i_X509_CRL.pod @@ -0,0 +1,37 @@ +=pod + +=head1 NAME + +d2i_X509_CRL, i2d_X509_CRL, d2i_X509_CRL_bio, d2i_509_CRL_fp, +i2d_X509_CRL_bio, i2d_X509_CRL_fp - PKCS#10 certificate request functions. + +=head1 SYNOPSIS + + #include + + X509_CRL *d2i_X509_CRL(X509_CRL **a, unsigned char **pp, long length); + int i2d_X509_CRL(X509_CRL *a, unsigned char **pp); + + X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **x); + X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **x); + + int i2d_X509_CRL_bio(X509_CRL *x, BIO *bp); + int i2d_X509_CRL_fp(X509_CRL *x, FILE *fp); + +=head1 DESCRIPTION + +These functions decode and encode an X509 CRL (certificate revocation +list). + +Othewise the functions behave in a similar way to d2i_X509() and i2d_X509() +described in the L manual page. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +TBA + +=cut diff --git a/doc/crypto/d2i_X509_REQ.pod b/doc/crypto/d2i_X509_REQ.pod new file mode 100644 index 000000000..be4ad6825 --- /dev/null +++ b/doc/crypto/d2i_X509_REQ.pod @@ -0,0 +1,36 @@ +=pod + +=head1 NAME + +d2i_X509_REQ, i2d_X509_REQ, d2i_X509_REQ_bio, d2i_X509_REQ_fp, +i2d_X509_REQ_bio, i2d_X509_REQ_fp - PKCS#10 certificate request functions. + +=head1 SYNOPSIS + + #include + + X509_REQ *d2i_X509_REQ(X509_REQ **a, unsigned char **pp, long length); + int i2d_X509_REQ(X509_REQ *a, unsigned char **pp); + + X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **x); + X509_REQ *d2i_X509_REQ_fp(FILE *fp, X509_REQ **x); + + int i2d_X509_REQ_bio(X509_REQ *x, BIO *bp); + int i2d_X509_REQ_fp(X509_REQ *x, FILE *fp); + +=head1 DESCRIPTION + +These functions decode and encode a PKCS#10 certificate request. + +Othewise these behave in a similar way to d2i_X509() and i2d_X509() +described in the L manual page. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +TBA + +=cut diff --git a/doc/crypto/d2i_X509_SIG.pod b/doc/crypto/d2i_X509_SIG.pod new file mode 100644 index 000000000..e48fd79a5 --- /dev/null +++ b/doc/crypto/d2i_X509_SIG.pod @@ -0,0 +1,30 @@ +=pod + +=head1 NAME + +d2i_X509_SIG, i2d_X509_SIG - DigestInfo functions. + +=head1 SYNOPSIS + + #include + + X509_SIG *d2i_X509_SIG(X509_SIG **a, unsigned char **pp, long length); + int i2d_X509_SIG(X509_SIG *a, unsigned char **pp); + +=head1 DESCRIPTION + +These functions decode and encode an X509_SIG structure which is +equivalent to the B structure defined in PKCS#1 and PKCS#7. + +Othewise these behave in a similar way to d2i_X509() and i2d_X509() +described in the L manual page. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +TBA + +=cut