#include <stdio.h>
#include <string.h>
#include <malloc.h>

#include "ssl.h"
#include "envelope.h"
#include "objects.h"
#include "pem.h"
#include "x509.h"

char               *makespkac(RSA * rsa, char *challenge)
{
	int                 n;
	unsigned char      *ep, *cp;

	NETSCAPE_SPKI      *spki;
	EVP_PKEY            pkey;
	EVP_ENCODE_CTX      baseout;

	spki = NETSCAPE_SPKI_new();
	spki->spkac->pubkey->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption);
	spki->spkac->pubkey->algor->parameter = ASN1_TYPE_new();
	spki->spkac->pubkey->algor->parameter->type = V_ASN1_NULL;
	n = i2d_RSAPublicKey(rsa, NULL);
	cp = malloc(n + 1);
	ep = cp;
	i2d_RSAPublicKey(rsa, &ep);
	spki->spkac->pubkey->public_key->length = n;
	spki->spkac->pubkey->public_key->data = cp;
	spki->spkac->challenge->type = V_ASN1_IA5STRING;
	cp = malloc(strlen(challenge) + 1);
	strcpy(cp, challenge);
	spki->spkac->challenge->data = cp;
	spki->spkac->challenge->length = strlen(challenge);
	spki->sig_algor->algorithm = OBJ_nid2obj(NID_md5withRSAEncryption);
	spki->sig_algor->parameter = ASN1_TYPE_new();
	spki->sig_algor->parameter->type = V_ASN1_NULL;
	pkey.type = EVP_PKEY_RSA;
	pkey.pkey.rsa = rsa;
	NETSCAPE_SPKI_sign(spki, &pkey, EVP_md5());

	n = i2d_NETSCAPE_SPKI(spki, NULL);
	cp = malloc(n + 1);
	ep = cp;
	n = i2d_NETSCAPE_SPKI(spki, &ep);
	NETSCAPE_SPKI_free(spki);

	ep = malloc(n * 4 / 3 + 4);
	memset(ep, 0, n * 4 / 3 + 4);
	EVP_EncodeInit(&baseout);
	EVP_EncodeUpdate(&baseout, ep, &n, cp, n);
	EVP_EncodeFinal(&baseout, &ep[n], &n);

	free(cp);
	cp = ep;
	while (cp) {
		if ((cp = strchr(cp, '\n')))
			strcpy(cp, cp + 1);
	}
	return ep;
}

int                 main(int argc, char *argv[])
{
	FILE               *fp;
	RSA                *rsa;
	char               *c;

	if (argc != 3) {
		printf("usage: spkac rsakey.pem challenge_string\n");
		exit(-1);
	}

	fp = fopen(argv[1], "r");
	rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL);
	fclose(fp);

	c = makespkac(rsa, argv[2]);
	printf("%s\n", c);
	free(c);

	return 0;
}
