This is a multi-part message in MIME format.

------=_NextPart_000_0046_01C6E3C6.9341CA70
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit



Hi,

Awhile ago I mentioned wanting to get proxy support (RFC 3280, yes it's
expired, but in use) into openssl as simply as possible.

I've built the attached module, that does what I wanted. What's the best way
to try and get this integrated into the standard distribution?

Thanks,

--Ivan

------=_NextPart_000_0046_01C6E3C6.9341CA70
Content-Type: text/plain;
name="x509_proxy.c"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="x509_proxy.c"

/* apps/x509_proxy.c */
/* Copyright (C) 2006 Ivan R. Judson (judson@mcs.anl.gov)
* All rights reserved.
*
* The licence and distribution terms for any publically available =
version or
* derivative of this code cannot be changed. i.e. this code cannot =
simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/

#include
#include
#include
#include
#ifdef OPENSSL_NO_STDIO
#define APPS_WIN16
#endif
#include "apps.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef OPENSSL_NO_RSA
#include
#endif

#undef PROG
#define PROG x509_proxy_main

#undef POSTFIX
#define POSTFIX ".srl"
#define DEF_DAYS 1

static const char *x509_proxy_usage[]=3D{
"usage: x509_proxy args\n",
" -inform arg - input format - default PEM (one of DER, NET or =
PEM)\n",
" -keyform arg - private key format - default PEM\n",
" -cert arg - input certificate\n",
" -key arg - input private key\n",
" -proxy arg - input proxy certificate\n",
" -out arg - output file - default stdout\n",
" -passin arg - private key password source\n",
" -days arg - How long till expiry of a signed certificate - def =
30 days\n",
" -md2/-md5/-sha1/-mdc2 - digest to use\n",
" -create - create a proxy certificate\n",
" -info - print the certificate in text form\n",
NULL
};

#ifndef OPENSSL_NO_RSA
static int MS_CALLBACK genrsa_cb(int p, int n, BN_GENCB *cb);
#endif

int MAIN(int, char **);

int MAIN(int argc, char **argv)
{
char *proxyfile=3DNULL, *outfile=3DNULL, *keyfile=3DNULL, =
*certfile=3DNULL;
char *alias=3DNULL, *passin=3DNULL, *passargin=3DNULL;
const char **pp;
int ret=3D1, num, badops=3D0, informat, keyformat, info=3D0;
int create=3D0, days=3DDEF_DAYS, modulus=3D512;
unsigned long nmflag =3D 0, certflag =3D 0;
const EVP_MD *md_alg, *digest=3DEVP_md5();
ASN1_INTEGER *sno =3D NULL;
BIO *out=3DNULL, *STDout=3DNULL;
ENGINE *e =3D NULL;
EVP_PKEY *userkey=3DNULL;
STACK_OF(ASN1_OBJECT) *trust =3D NULL, *reject =3D NULL;
X509 *usercert=3DNULL, *proxy=3DNULL;
#ifndef OPENSSL_NO_ENGINE
char *engine=3DNULL;
#endif

apps_startup();

if (bio_err =3D=3D NULL)
bio_err=3DBIO_new_fp(stderr,BIO_NOCLOSE);

if (!load_config(bio_err, NULL))
goto end;
STDout=3DBIO_new_fp(stdout,BIO_NOCLOSE);
#ifdef OPENSSL_SYS_VMS
{
BIO *tmpbio =3D BIO_new(BIO_f_linebuffer());
STDout =3D BIO_push(tmpbio, STDout);
}
#endif

informat=3DFORMAT_PEM;
keyformat=3DFORMAT_PEM;

argc--;
argv++;
num=3D0;

while (argc >=3D 1) {
if (strcmp(*argv,"-inform") =3D=3D 0) {
if (--argc < 1) goto bad;
informat=3Dstr2fmt(*(++argv));
} else if (strcmp(*argv,"-keyform") =3D=3D 0) {
if (--argc < 1) goto bad;
keyformat=3Dstr2fmt(*(++argv));
} else if (strcmp(*argv,"-days") =3D=3D 0) {
if (--argc < 1) goto bad;
days=3Datoi(*(++argv));
if (days =3D=3D 0) {
BIO_printf(STDout,"bad number of days\n");
goto bad;
}
} else if (strcmp(*argv,"-passin") =3D=3D 0) {
if (--argc < 1) goto bad;
passargin=3D *(++argv);
} else if (strcmp(*argv,"-cert") =3D=3D 0) {
if (--argc < 1) goto bad;
certfile=3D *(++argv);
} else if (strcmp(*argv,"-key") =3D=3D 0) {
if (--argc < 1) goto bad;
keyfile=3D *(++argv);
} else if (strcmp(*argv,"-proxy") =3D=3D 0) {
if (--argc < 1) goto bad;
proxyfile=3D *(++argv);
} else if (strcmp(*argv,"-out") =3D=3D 0) {
if (--argc < 1) goto bad;
outfile=3D *(++argv);
} else if (strcmp(*argv,"-create") =3D=3D 0)
create =3D ++num;
else if (strcmp(*argv,"-info") =3D=3D 0)
info =3D ++num;
else if ((md_alg=3DEVP_get_digestbyname(*argv + 1)))
digest=3Dmd_alg;
else {
BIO_printf(bio_err,"unknown option %s\n",*argv);
badops=3D1;
break;
}
=09
argc--;
argv++;
}

if (badops) {
bad:
for (pp=3Dx509_proxy_usage; (*pp !=3D NULL); pp++)
BIO_printf(bio_err,"%s",*pp);
goto end;
}

/* Initialization */
#ifndef OPENSSL_NO_ENGINE
e =3D setup_engine(bio_err, engine, 0);
#endif

if (create)
app_RAND_load_file(NULL, bio_err, 0);
=20
ERR_load_crypto_strings();
=20
if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
BIO_printf(bio_err, "Error getting password\n");
goto end;
}

/* Create output file or filehandle */
OBJ_create("2.99999.3",
"SET.ex3","SET x509v3 extension 3");
=20
out=3DBIO_new(BIO_s_file());
=20
if (out =3D=3D NULL) {
ERR_print_errors(bio_err);
goto end;
}
=20
if (outfile =3D=3D NULL) {
BIO_set_fp(out,stdout,BIO_NOCLOSE);
#ifdef OPENSSL_SYS_VMS
{
BIO *tmpbio =3D BIO_new(BIO_f_linebuffer());
out =3D BIO_push(tmpbio, out);
}
#endif
} else {
if (BIO_write_filename(out,outfile) <=3D 0) {
perror(outfile);
goto end;
}
}

/* If print the proxy, print it! */
if (info) {
proxy =3D load_cert(bio_err, proxyfile, informat, NULL, e, =
"Certificate");
X509_print_ex(out, proxy, nmflag, certflag);
}

/* If create a new proxy, do that... */
if (create) {
long tout =3D 60*60*12*days;
unsigned long f4=3DRSA_F4;
EVP_PKEY *proxykey =3D EVP_PKEY_new(), *signkey =3D EVP_PKEY_new();
LHASH *hash =3D lh_new(NULL, NULL);
X509V3_CTX ctx;
X509_EXTENSION *ku_ext, *pci_ext;
X509_NAME *sname=3DNULL;
X509_NAME_ENTRY *cn=3DNULL;
RSA *rsa =3D RSA_new();
BN_GENCB cb;
BIGNUM *bn =3D BN_new();
=20
/* Create a new X509 Certificate to be the proxy */
proxy=3DX509_new();

/* Load the certificate */
if (certfile) {
usercert =3D load_cert(bio_err, certfile, informat, NULL, =
e,"Certificate");
if (usercert =3D=3D NULL) goto end;
while(X509_get_ext_count(usercert) > 0)=20
X509_delete_ext(usercert, 0);
}

/* Load the private key */
if (keyfile) {
userkey =3D load_key(bio_err, keyfile, FORMAT_PEM, 0,=20
NULL, e, "Private Key");
}
=20
/* Generate a new RSA private key */
BN_GENCB_set(&cb, genrsa_cb, bio_err);
BIO_printf(bio_err,
"Generating RSA private key, %d bit long modulus\n",
modulus);
if (!BN_set_word(bn, f4) ||=20
!RSA_generate_key_ex(rsa, modulus, bn, &cb) ||
!EVP_PKEY_assign_RSA(proxykey, rsa)) {
BN_free(bn);
RSA_free(rsa);
goto end;
}

/* Create the fancy proxy extensions */
X509V3_set_conf_lhash(&ctx, hash);
ku_ext =3D X509V3_EXT_conf(hash, &ctx, "keyUsage",=20
"Digital Signature, Key Encipherment, Data Encipherment");
X509_EXTENSION_set_critical(ku_ext, 1);

pci_ext =3D X509V3_EXT_conf(hash, &ctx, "proxyCertInfo",
"critical, language:Inherit all");
X509_EXTENSION_set_critical(pci_ext, 1);

/* Get a serial number, creating one if necessary */
if (sno) {
if (!X509_set_serialNumber(proxy, sno)) goto end;
} else {
if (!rand_serial(NULL, X509_get_serialNumber(proxy))) goto end;
}

/* Assign the bits to the proxy */
if (!X509_set_pubkey(proxy, proxykey)) goto end;
if (!X509_set_version(proxy, 2)) goto end;
if (X509_gmtime_adj(X509_get_notBefore(proxy), (long)0) =3D=3D NULL) =
goto end;
if (X509_gmtime_adj(X509_get_notAfter(proxy),(long)36 00*24*days) =
=3D=3D NULL)=20
goto end;
sname =3D X509_NAME_dup(X509_get_subject_name(usercert));
if (!X509_NAME_add_entry_by_txt(sname, "commonName", MBSTRING_ASC,=20
i2s_ASN1_INTEGER(NULL,=20
X509_get_serialNumber(proxy)),
-1, -1, 0))
goto end;
if (!X509_set_issuer_name(proxy, X509_get_subject_name(usercert)))=20
goto end;
if (!X509_set_subject_name(proxy, sname))=20
goto end;
if (!X509_add_ext(proxy, ku_ext, 1)) goto end;
if (!X509_add_ext(proxy, pci_ext, 1)) goto end;

/* Assign the user supplied private key to the signing key */
EVP_PKEY_assign_RSA(signkey, EVP_PKEY_get1_RSA(userkey));

/* sign the proxy */
if (!X509_sign(proxy, signkey, digest)) {
ERR_print_errors(bio_err);
RSA_free(rsa);
EVP_PKEY_free(proxykey);
goto end;
}

/* Print out the proxy */
if (!PEM_write_bio_X509(out, proxy)) {
BIO_printf(bio_err,"Unable to write proxy certificate\n");
ERR_print_errors(bio_err);
}
if (!PEM_write_bio_RSAPrivateKey(out, rsa, NULL, NULL, 0, NULL, =
NULL)) {
BIO_printf(bio_err,"Unable to write private key\n");
ERR_print_errors(bio_err);
}
if (!PEM_write_bio_X509(out, usercert)) {
BIO_printf(bio_err,"Unable to write user certificate\n");
ERR_print_errors(bio_err);
}

RSA_free(rsa);
}

ret=3D0;

/* Cleanup */
end:
if (create)
app_RAND_write_file(NULL, bio_err);
OBJ_cleanup();
BIO_free_all(out);
BIO_free_all(STDout);
X509_free(usercert);
EVP_PKEY_free(userkey);
ASN1_INTEGER_free(sno);
if (passin) OPENSSL_free(passin);
apps_shutdown();
OPENSSL_EXIT(ret);
}

static ASN1_INTEGER *x509_load_serial(char *CAfile, char *serialfile, =
int create)
{
char *buf =3D NULL, *p;
ASN1_INTEGER *bs =3D NULL;
BIGNUM *serial =3D NULL;
size_t len;

len =3D ((serialfile =3D=3D NULL)
?(strlen(CAfile)+strlen(POSTFIX)+1)
strlen(serialfile)))+1;
buf=3DOPENSSL_malloc(len);
if (buf =3D=3D NULL) { BIO_printf(bio_err,"out of mem\n"); goto end; }
if (serialfile =3D=3D NULL)
{
BUF_strlcpy(buf,CAfile,len);
for (p=3Dbuf; *p; p++)
if (*p =3D=3D '.')
{
*p=3D'\0';
break;
}
BUF_strlcat(buf,POSTFIX,len);
}
else
BUF_strlcpy(buf,serialfile,len);

serial =3D load_serial(buf, create, NULL);
if (serial =3D=3D NULL) goto end;

if (!BN_add_word(serial,1))
{ BIO_printf(bio_err,"add_word failure\n"); goto end; }

if (!save_serial(buf, NULL, serial, &bs)) goto end;

end:
if (buf) OPENSSL_free(buf);
BN_free(serial);
return bs;
}

#ifndef OPENSSL_NO_RSA
static int MS_CALLBACK genrsa_cb(int p, int n, BN_GENCB *cb)
{
char c=3D'*';

if (p =3D=3D 0) c=3D'.';
if (p =3D=3D 1) c=3D'+';
if (p =3D=3D 2) c=3D'*';
if (p =3D=3D 3) c=3D'\n';
BIO_write(cb->arg,&c,1);
(void)BIO_flush(cb->arg);
#ifdef LINT
p=3Dn;
#endif
return 1;
}
#endif


------=_NextPart_000_0046_01C6E3C6.9341CA70--

__________________________________________________ ____________________
OpenSSL Project http://www.openssl.org
Development Mailing List openssl-dev@openssl.org
Automated List Manager majordomo@openssl.org