diff -N -r -u -x CVS -x certs clean/apps/Makefile proxy/apps/Makefile --- clean/apps/Makefile 2006-10-03 14:17:29.000000000 -0500 +++ proxy/apps/Makefile 2006-10-03 13:48:23.000000000 -0500 @@ -37,7 +37,7 @@ E_EXE= verify asn1pars req dgst dh dhparam enc passwd gendh errstr \ ca crl rsa rsautl dsa dsaparam ec ecparam \ - x509 genrsa gendsa genpkey s_server s_client speed \ + x509 x509_proxy genrsa gendsa genpkey s_server s_client speed \ s_time version pkcs7 crl2pkcs7 sess_id ciphers nseq pkcs12 \ pkcs8 pkey pkeyparam pkeyutl spkac smime rand engine ocsp prime ts @@ -53,7 +53,7 @@ E_OBJ= verify.o asn1pars.o req.o dgst.o dh.o dhparam.o enc.o passwd.o gendh.o errstr.o \ ca.o pkcs7.o crl2p7.o crl.o \ rsa.o rsautl.o dsa.o dsaparam.o ec.o ecparam.o \ - x509.o genrsa.o gendsa.o genpkey.o s_server.o s_client.o speed.o \ + x509.o x509_proxy.o genrsa.o gendsa.o genpkey.o s_server.o s_client.o speed.o \ s_time.o $(A_OBJ) $(S_OBJ) $(RAND_OBJ) version.o sess_id.o \ ciphers.o nseq.o pkcs12.o pkcs8.o pkey.o pkeyparam.o pkeyutl.o \ spkac.o smime.o rand.o engine.o ocsp.o prime.o ts.o @@ -61,7 +61,7 @@ E_SRC= verify.c asn1pars.c req.c dgst.c dh.c enc.c passwd.c gendh.c errstr.c ca.c \ pkcs7.c crl2p7.c crl.c \ rsa.c rsautl.c dsa.c dsaparam.c ec.c ecparam.c \ - x509.c genrsa.c gendsa.c genpkey.c s_server.c s_client.c speed.c \ + x509.c x509_proxy.c genrsa.c gendsa.c genpkey.c s_server.c s_client.c speed.c \ s_time.c $(A_SRC) $(S_SRC) $(RAND_SRC) version.c sess_id.c \ ciphers.c nseq.c pkcs12.c pkcs8.c pkey.c pkeyparam.c pkeyutl.c \ spkac.c smime.c rand.c engine.c ocsp.c prime.c ts.c diff -N -r -u -x CVS -x certs clean/apps/progs.h proxy/apps/progs.h --- clean/apps/progs.h 2006-07-08 19:53:44.000000000 -0500 +++ proxy/apps/progs.h 2006-10-03 13:29:22.000000000 -0500 @@ -20,6 +20,7 @@ extern int ec_main(int argc,char *argv[]); extern int ecparam_main(int argc,char *argv[]); extern int x509_main(int argc,char *argv[]); +extern int x509_proxy_main(int argc,char *argv[]); extern int genrsa_main(int argc,char *argv[]); extern int gendsa_main(int argc,char *argv[]); extern int genpkey_main(int argc,char *argv[]); @@ -97,6 +98,7 @@ {FUNC_TYPE_GENERAL,"ecparam",ecparam_main}, #endif {FUNC_TYPE_GENERAL,"x509",x509_main}, + {FUNC_TYPE_GENERAL,"x509_proxy",x509_proxy_main}, #ifndef OPENSSL_NO_RSA {FUNC_TYPE_GENERAL,"genrsa",genrsa_main}, #endif diff -N -r -u -x CVS -x certs clean/apps/x509_proxy.c proxy/apps/x509_proxy.c --- clean/apps/x509_proxy.c 1969-12-31 18:00:00.000000000 -0600 +++ proxy/apps/x509_proxy.c 2006-10-03 13:12:39.000000000 -0500 @@ -0,0 +1,385 @@ +/* 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[]={ + "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=NULL, *outfile=NULL, *keyfile=NULL, *certfile=NULL; + char *alias=NULL, *passin=NULL, *passargin=NULL; + const char **pp; + int ret=1, num, badops=0, informat, keyformat, info=0; + int create=0, days=DEF_DAYS, modulus=512; + unsigned long nmflag = 0, certflag = 0; + const EVP_MD *md_alg, *digest=EVP_md5(); + ASN1_INTEGER *sno = NULL; + BIO *out=NULL, *STDout=NULL; + ENGINE *e = NULL; + EVP_PKEY *userkey=NULL; + STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL; + X509 *usercert=NULL, *proxy=NULL; +#ifndef OPENSSL_NO_ENGINE + char *engine=NULL; +#endif + + apps_startup(); + + if (bio_err == NULL) + bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); + + if (!load_config(bio_err, NULL)) + goto end; + STDout=BIO_new_fp(stdout,BIO_NOCLOSE); +#ifdef OPENSSL_SYS_VMS + { + BIO *tmpbio = BIO_new(BIO_f_linebuffer()); + STDout = BIO_push(tmpbio, STDout); + } +#endif + + informat=FORMAT_PEM; + keyformat=FORMAT_PEM; + + argc--; + argv++; + num=0; + + while (argc >= 1) { + if (strcmp(*argv,"-inform") == 0) { + if (--argc < 1) goto bad; + informat=str2fmt(*(++argv)); + } else if (strcmp(*argv,"-keyform") == 0) { + if (--argc < 1) goto bad; + keyformat=str2fmt(*(++argv)); + } else if (strcmp(*argv,"-days") == 0) { + if (--argc < 1) goto bad; + days=atoi(*(++argv)); + if (days == 0) { + BIO_printf(STDout,"bad number of days\n"); + goto bad; + } + } else if (strcmp(*argv,"-passin") == 0) { + if (--argc < 1) goto bad; + passargin= *(++argv); + } else if (strcmp(*argv,"-cert") == 0) { + if (--argc < 1) goto bad; + certfile= *(++argv); + } else if (strcmp(*argv,"-key") == 0) { + if (--argc < 1) goto bad; + keyfile= *(++argv); + } else if (strcmp(*argv,"-proxy") == 0) { + if (--argc < 1) goto bad; + proxyfile= *(++argv); + } else if (strcmp(*argv,"-out") == 0) { + if (--argc < 1) goto bad; + outfile= *(++argv); + } else if (strcmp(*argv,"-create") == 0) + create = ++num; + else if (strcmp(*argv,"-info") == 0) + info = ++num; + else if ((md_alg=EVP_get_digestbyname(*argv + 1))) + digest=md_alg; + else { + BIO_printf(bio_err,"unknown option %s\n",*argv); + badops=1; + break; + } + + argc--; + argv++; + } + + if (badops) { + bad: + for (pp=x509_proxy_usage; (*pp != NULL); pp++) + BIO_printf(bio_err,"%s",*pp); + goto end; + } + + /* Initialization */ +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + if (create) + app_RAND_load_file(NULL, bio_err, 0); + + ERR_load_crypto_strings(); + + 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"); + + out=BIO_new(BIO_s_file()); + + if (out == NULL) { + ERR_print_errors(bio_err); + goto end; + } + + if (outfile == NULL) { + BIO_set_fp(out,stdout,BIO_NOCLOSE); +#ifdef OPENSSL_SYS_VMS + { + BIO *tmpbio = BIO_new(BIO_f_linebuffer()); + out = BIO_push(tmpbio, out); + } +#endif + } else { + if (BIO_write_filename(out,outfile) <= 0) { + perror(outfile); + goto end; + } + } + + /* If print the proxy, print it! */ + if (info) { + proxy = 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 = 60*60*12*days; + unsigned long f4=RSA_F4; + EVP_PKEY *proxykey = EVP_PKEY_new(), *signkey = EVP_PKEY_new(); + LHASH *hash = lh_new(NULL, NULL); + X509V3_CTX ctx; + X509_EXTENSION *ku_ext, *pci_ext; + X509_NAME *sname=NULL; + X509_NAME_ENTRY *cn=NULL; + RSA *rsa = RSA_new(); + BN_GENCB cb; + BIGNUM *bn = BN_new(); + + /* Create a new X509 Certificate to be the proxy */ + proxy=X509_new(); + + /* Load the certificate */ + if (certfile) { + usercert = load_cert(bio_err, certfile, informat, NULL, e,"Certificate"); + if (usercert == NULL) goto end; + while(X509_get_ext_count(usercert) > 0) + X509_delete_ext(usercert, 0); + } + + /* Load the private key */ + if (keyfile) { + userkey = load_key(bio_err, keyfile, FORMAT_PEM, 0, + NULL, e, "Private Key"); + } + + /* 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) || + !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 = X509V3_EXT_conf(hash, &ctx, "keyUsage", + "Digital Signature, Key Encipherment, Data Encipherment"); + X509_EXTENSION_set_critical(ku_ext, 1); + + pci_ext = 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) == NULL) goto end; + if (X509_gmtime_adj(X509_get_notAfter(proxy),(long)3600*24*days) == NULL) + goto end; + sname = X509_NAME_dup(X509_get_subject_name(usercert)); + if (!X509_NAME_add_entry_by_txt(sname, "commonName", MBSTRING_ASC, + i2s_ASN1_INTEGER(NULL, + X509_get_serialNumber(proxy)), + -1, -1, 0)) + goto end; + if (!X509_set_issuer_name(proxy, X509_get_subject_name(usercert))) + goto end; + if (!X509_set_subject_name(proxy, sname)) + 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=0; + + /* 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 = NULL, *p; + ASN1_INTEGER *bs = NULL; + BIGNUM *serial = NULL; + size_t len; + + len = ((serialfile == NULL) + ?(strlen(CAfile)+strlen(POSTFIX)+1) + :(strlen(serialfile)))+1; + buf=OPENSSL_malloc(len); + if (buf == NULL) { BIO_printf(bio_err,"out of mem\n"); goto end; } + if (serialfile == NULL) + { + BUF_strlcpy(buf,CAfile,len); + for (p=buf; *p; p++) + if (*p == '.') + { + *p='\0'; + break; + } + BUF_strlcat(buf,POSTFIX,len); + } + else + BUF_strlcpy(buf,serialfile,len); + + serial = load_serial(buf, create, NULL); + if (serial == 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='*'; + + if (p == 0) c='.'; + if (p == 1) c='+'; + if (p == 2) c='*'; + if (p == 3) c='\n'; + BIO_write(cb->arg,&c,1); + (void)BIO_flush(cb->arg); +#ifdef LINT + p=n; +#endif + return 1; +} +#endif +