1/* NOCW */
2/* demos/spkigen.c
3 * 18-Mar-1997 - eay - A quick hack :-)
4 * 		version 1.1, it would probably help to save or load the
5 *		private key :-)
6 */
7#include <stdio.h>
8#include <stdlib.h>
9#include <openssl/err.h>
10#include <openssl/asn1.h>
11#include <openssl/objects.h>
12#include <openssl/evp.h>
13#include <openssl/x509.h>
14#include <openssl/pem.h>
15
16/* The following two don't exist in SSLeay but they are in here as
17 * examples */
18#define PEM_write_SPKI(fp,x) \
19	PEM_ASN1_write((int (*)())i2d_NETSCAPE_SPKI,"SPKI",fp,\
20			(char *)x,NULL,NULL,0,NULL)
21int SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey);
22
23/* These are defined in the next version of SSLeay */
24int EVP_PKEY_assign(EVP_PKEY *pkey, int type,char *key);
25#define RSA_F4	0x10001
26#define EVP_PKEY_assign_RSA(pkey,rsa) EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
27					(char *)(rsa))
28
29int main(argc,argv)
30int argc;
31char *argv[];
32	{
33	RSA *rsa=NULL;
34	NETSCAPE_SPKI *spki=NULL;
35	EVP_PKEY *pkey=NULL;
36	char buf[128];
37	int ok=0,i;
38	FILE *fp;
39
40	pkey=EVP_PKEY_new();
41
42	if (argc < 2)
43		{
44		/* Generate an RSA key, the random state should have been seeded
45		 * with lots of calls to RAND_seed(....) */
46		fprintf(stderr,"generating RSA key, could take some time...\n");
47		if ((rsa=RSA_generate_key(512,RSA_F4,NULL)) == NULL) goto err;
48		}
49	else
50		{
51		if ((fp=fopen(argv[1],"r")) == NULL)
52			{ perror(argv[1]); goto err; }
53		if ((rsa=PEM_read_RSAPrivateKey(fp,NULL,NULL)) == NULL)
54			goto err;
55		fclose(fp);
56		}
57
58	if (!EVP_PKEY_assign_RSA(pkey,rsa)) goto err;
59	rsa=NULL;
60
61	/* lets make the spki and set the public key and challenge */
62	if ((spki=NETSCAPE_SPKI_new()) == NULL) goto err;
63
64	if (!SPKI_set_pubkey(spki,pkey)) goto err;
65
66	fprintf(stderr,"please enter challenge string:");
67	fflush(stderr);
68	buf[0]='\0';
69	fgets(buf,sizeof buf,stdin);
70	i=strlen(buf);
71	if (i > 0) buf[--i]='\0';
72	if (!ASN1_STRING_set((ASN1_STRING *)spki->spkac->challenge,
73		buf,i)) goto err;
74
75	if (!NETSCAPE_SPKI_sign(spki,pkey,EVP_md5())) goto err;
76	PEM_write_SPKI(stdout,spki);
77	if (argc < 2)
78		PEM_write_RSAPrivateKey(stdout,pkey->pkey.rsa,NULL,NULL,0,NULL);
79
80	ok=1;
81err:
82	if (!ok)
83		{
84		fprintf(stderr,"something bad happened....");
85		ERR_print_errors_fp(stderr);
86		}
87	NETSCAPE_SPKI_free(spki);
88	EVP_PKEY_free(pkey);
89	exit(!ok);
90	}
91
92/* This function is in the next version of SSLeay */
93int EVP_PKEY_assign(pkey,type,key)
94EVP_PKEY *pkey;
95int type;
96char *key;
97	{
98	if (pkey == NULL) return(0);
99	if (pkey->pkey.ptr != NULL)
100		{
101		if (pkey->type == EVP_PKEY_RSA)
102			RSA_free(pkey->pkey.rsa);
103		/* else memory leak */
104		}
105	pkey->type=type;
106	pkey->pkey.ptr=key;
107	return(1);
108	}
109
110/* While I have a
111 * X509_set_pubkey() and X509_REQ_set_pubkey(), SPKI_set_pubkey() does
112 * not currently exist so here is a version of it.
113 * The next SSLeay release will probably have
114 * X509_set_pubkey(),
115 * X509_REQ_set_pubkey() and
116 * NETSCAPE_SPKI_set_pubkey()
117 * as macros calling the same function */
118int SPKI_set_pubkey(x,pkey)
119NETSCAPE_SPKI *x;
120EVP_PKEY *pkey;
121	{
122	int ok=0;
123	X509_PUBKEY *pk;
124	X509_ALGOR *a;
125	ASN1_OBJECT *o;
126	unsigned char *s,*p;
127	int i;
128
129	if (x == NULL) return(0);
130
131	if ((pk=X509_PUBKEY_new()) == NULL) goto err;
132	a=pk->algor;
133
134	/* set the algorithm id */
135	if ((o=OBJ_nid2obj(pkey->type)) == NULL) goto err;
136	ASN1_OBJECT_free(a->algorithm);
137	a->algorithm=o;
138
139	/* Set the parameter list */
140	if ((a->parameter == NULL) || (a->parameter->type != V_ASN1_NULL))
141		{
142		ASN1_TYPE_free(a->parameter);
143		a->parameter=ASN1_TYPE_new();
144		a->parameter->type=V_ASN1_NULL;
145		}
146	i=i2d_PublicKey(pkey,NULL);
147	if ((s=(unsigned char *)malloc(i+1)) == NULL) goto err;
148	p=s;
149	i2d_PublicKey(pkey,&p);
150	if (!ASN1_BIT_STRING_set(pk->public_key,s,i)) goto err;
151	free(s);
152
153	X509_PUBKEY_free(x->spkac->pubkey);
154	x->spkac->pubkey=pk;
155	pk=NULL;
156	ok=1;
157err:
158	if (pk != NULL) X509_PUBKEY_free(pk);
159	return(ok);
160	}
161
162