xref: /plan9-contrib/sys/src/cmd/auth/factotum/rsa.c (revision 7f0b57c67146be0d1988c0e09c92be045222e800)
12ebbfa15SDavid du Colombier /*
2*7f0b57c6SDavid du Colombier  * RSA authentication.
32ebbfa15SDavid du Colombier  *
4*7f0b57c6SDavid du Colombier  * Old ssh client protocol:
52ebbfa15SDavid du Colombier  *	read public key
62ebbfa15SDavid du Colombier  *		if you don't like it, read another, repeat
72ebbfa15SDavid du Colombier  *	write challenge
82ebbfa15SDavid du Colombier  *	read response
9*7f0b57c6SDavid du Colombier  *
102ebbfa15SDavid du Colombier  * all numbers are hexadecimal biginits parsable with strtomp.
112ebbfa15SDavid du Colombier  *
12*7f0b57c6SDavid du Colombier  * Sign (PKCS #1 using hash=sha1 or hash=md5)
13*7f0b57c6SDavid du Colombier  *	write hash(msg)
14*7f0b57c6SDavid du Colombier  *	read signature(hash(msg))
15*7f0b57c6SDavid du Colombier  *
16*7f0b57c6SDavid du Colombier  * Verify:
17*7f0b57c6SDavid du Colombier  *	write hash(msg)
18*7f0b57c6SDavid du Colombier  *	write signature(hash(msg))
19*7f0b57c6SDavid du Colombier  *	read ok or fail
202ebbfa15SDavid du Colombier  */
212ebbfa15SDavid du Colombier 
222ebbfa15SDavid du Colombier #include "dat.h"
232ebbfa15SDavid du Colombier 
242ebbfa15SDavid du Colombier enum {
252ebbfa15SDavid du Colombier 	CHavePub,
262ebbfa15SDavid du Colombier 	CHaveResp,
27*7f0b57c6SDavid du Colombier 	VNeedHash,
28*7f0b57c6SDavid du Colombier 	VNeedSig,
29*7f0b57c6SDavid du Colombier 	VHaveResp,
30*7f0b57c6SDavid du Colombier 	SNeedHash,
31*7f0b57c6SDavid du Colombier 	SHaveResp,
322ebbfa15SDavid du Colombier 	Maxphase,
332ebbfa15SDavid du Colombier };
342ebbfa15SDavid du Colombier 
352ebbfa15SDavid du Colombier static char *phasenames[] = {
362ebbfa15SDavid du Colombier [CHavePub]	"CHavePub",
372ebbfa15SDavid du Colombier [CHaveResp]	"CHaveResp",
38*7f0b57c6SDavid du Colombier [VNeedHash]	"VNeedHash",
39*7f0b57c6SDavid du Colombier [VNeedSig]	"VNeedSig",
40*7f0b57c6SDavid du Colombier [VHaveResp]	"VHaveResp",
41*7f0b57c6SDavid du Colombier [SNeedHash]	"SNeedHash",
42*7f0b57c6SDavid du Colombier [SHaveResp]	"SHaveResp",
432ebbfa15SDavid du Colombier };
442ebbfa15SDavid du Colombier 
452ebbfa15SDavid du Colombier struct State
462ebbfa15SDavid du Colombier {
472ebbfa15SDavid du Colombier 	RSApriv *priv;
482ebbfa15SDavid du Colombier 	mpint *resp;
492ebbfa15SDavid du Colombier 	int off;
502ebbfa15SDavid du Colombier 	Key *key;
51*7f0b57c6SDavid du Colombier 	mpint *digest;
52*7f0b57c6SDavid du Colombier 	int sigresp;
532ebbfa15SDavid du Colombier };
542ebbfa15SDavid du Colombier 
55*7f0b57c6SDavid du Colombier static mpint* mkdigest(RSApub *key, char *hashalg, uchar *hash, uint dlen);
56*7f0b57c6SDavid du Colombier 
572ebbfa15SDavid du Colombier static RSApriv*
readrsapriv(Key * k)582ebbfa15SDavid du Colombier readrsapriv(Key *k)
592ebbfa15SDavid du Colombier {
602ebbfa15SDavid du Colombier 	char *a;
612ebbfa15SDavid du Colombier 	RSApriv *priv;
622ebbfa15SDavid du Colombier 
632ebbfa15SDavid du Colombier 	priv = rsaprivalloc();
642ebbfa15SDavid du Colombier 
652ebbfa15SDavid du Colombier 	if((a=_strfindattr(k->attr, "ek"))==nil || (priv->pub.ek=strtomp(a, nil, 16, nil))==nil)
662ebbfa15SDavid du Colombier 		goto Error;
672ebbfa15SDavid du Colombier 	if((a=_strfindattr(k->attr, "n"))==nil || (priv->pub.n=strtomp(a, nil, 16, nil))==nil)
682ebbfa15SDavid du Colombier 		goto Error;
69*7f0b57c6SDavid du Colombier 	if(k->privattr == nil)		/* only public half */
70*7f0b57c6SDavid du Colombier 		return priv;
712ebbfa15SDavid du Colombier 	if((a=_strfindattr(k->privattr, "!p"))==nil || (priv->p=strtomp(a, nil, 16, nil))==nil)
722ebbfa15SDavid du Colombier 		goto Error;
732ebbfa15SDavid du Colombier 	if((a=_strfindattr(k->privattr, "!q"))==nil || (priv->q=strtomp(a, nil, 16, nil))==nil)
742ebbfa15SDavid du Colombier 		goto Error;
752ebbfa15SDavid du Colombier 	if((a=_strfindattr(k->privattr, "!kp"))==nil || (priv->kp=strtomp(a, nil, 16, nil))==nil)
762ebbfa15SDavid du Colombier 		goto Error;
772ebbfa15SDavid du Colombier 	if((a=_strfindattr(k->privattr, "!kq"))==nil || (priv->kq=strtomp(a, nil, 16, nil))==nil)
782ebbfa15SDavid du Colombier 		goto Error;
792ebbfa15SDavid du Colombier 	if((a=_strfindattr(k->privattr, "!c2"))==nil || (priv->c2=strtomp(a, nil, 16, nil))==nil)
802ebbfa15SDavid du Colombier 		goto Error;
812ebbfa15SDavid du Colombier 	if((a=_strfindattr(k->privattr, "!dk"))==nil || (priv->dk=strtomp(a, nil, 16, nil))==nil)
822ebbfa15SDavid du Colombier 		goto Error;
832ebbfa15SDavid du Colombier 	return priv;
842ebbfa15SDavid du Colombier 
852ebbfa15SDavid du Colombier Error:
862ebbfa15SDavid du Colombier 	rsaprivfree(priv);
872ebbfa15SDavid du Colombier 	return nil;
882ebbfa15SDavid du Colombier }
892ebbfa15SDavid du Colombier 
902ebbfa15SDavid du Colombier static int
rsainit(Proto *,Fsstate * fss)912ebbfa15SDavid du Colombier rsainit(Proto*, Fsstate *fss)
922ebbfa15SDavid du Colombier {
93*7f0b57c6SDavid du Colombier 	Keyinfo ki;
942ebbfa15SDavid du Colombier 	State *s;
95*7f0b57c6SDavid du Colombier 	char *role;
962ebbfa15SDavid du Colombier 
97*7f0b57c6SDavid du Colombier 	if((role = _strfindattr(fss->attr, "role")) == nil)
98*7f0b57c6SDavid du Colombier 		return failure(fss, "rsa role not specified");
99*7f0b57c6SDavid du Colombier 	if(strcmp(role, "client") == 0)
100*7f0b57c6SDavid du Colombier 		fss->phase = CHavePub;
101*7f0b57c6SDavid du Colombier 	else if(strcmp(role, "sign") == 0)
102*7f0b57c6SDavid du Colombier 		fss->phase = SNeedHash;
103*7f0b57c6SDavid du Colombier 	else if(strcmp(role, "verify") == 0)
104*7f0b57c6SDavid du Colombier 		fss->phase = VNeedHash;
105*7f0b57c6SDavid du Colombier 	else
106*7f0b57c6SDavid du Colombier 		return failure(fss, "rsa role %s unimplemented", role);
1072ebbfa15SDavid du Colombier 
1082ebbfa15SDavid du Colombier 	s = emalloc(sizeof *s);
1092ebbfa15SDavid du Colombier 	fss->phasename = phasenames;
1102ebbfa15SDavid du Colombier 	fss->maxphase = Maxphase;
1112ebbfa15SDavid du Colombier 	fss->ps = s;
112*7f0b57c6SDavid du Colombier 
113*7f0b57c6SDavid du Colombier 	switch(fss->phase){
114*7f0b57c6SDavid du Colombier 	case SNeedHash:
115*7f0b57c6SDavid du Colombier 	case VNeedHash:
116*7f0b57c6SDavid du Colombier 		mkkeyinfo(&ki, fss, nil);
117*7f0b57c6SDavid du Colombier 		if(findkey(&s->key, &ki, nil) != RpcOk)
118*7f0b57c6SDavid du Colombier 			return failure(fss, nil);
119*7f0b57c6SDavid du Colombier 		/* signing needs private key */
120*7f0b57c6SDavid du Colombier 		if(fss->phase == SNeedHash && s->key->privattr == nil)
121*7f0b57c6SDavid du Colombier 			return failure(fss,
122*7f0b57c6SDavid du Colombier 				"missing private half of key -- cannot sign");
123*7f0b57c6SDavid du Colombier 	}
1242ebbfa15SDavid du Colombier 	return RpcOk;
1252ebbfa15SDavid du Colombier }
1262ebbfa15SDavid du Colombier 
1272ebbfa15SDavid du Colombier static int
rsaread(Fsstate * fss,void * va,uint * n)1282ebbfa15SDavid du Colombier rsaread(Fsstate *fss, void *va, uint *n)
1292ebbfa15SDavid du Colombier {
1302ebbfa15SDavid du Colombier 	RSApriv *priv;
1312ebbfa15SDavid du Colombier 	State *s;
132*7f0b57c6SDavid du Colombier 	mpint *m;
133260f7b65SDavid du Colombier 	Keyinfo ki;
134*7f0b57c6SDavid du Colombier 	int len, r;
1352ebbfa15SDavid du Colombier 
1362ebbfa15SDavid du Colombier 	s = fss->ps;
1372ebbfa15SDavid du Colombier 	switch(fss->phase){
1382ebbfa15SDavid du Colombier 	default:
1392ebbfa15SDavid du Colombier 		return phaseerror(fss, "read");
1402ebbfa15SDavid du Colombier 	case CHavePub:
1412ebbfa15SDavid du Colombier 		if(s->key){
1422ebbfa15SDavid du Colombier 			closekey(s->key);
1432ebbfa15SDavid du Colombier 			s->key = nil;
1442ebbfa15SDavid du Colombier 		}
145260f7b65SDavid du Colombier 		mkkeyinfo(&ki, fss, nil);
146260f7b65SDavid du Colombier 		ki.skip = s->off;
147260f7b65SDavid du Colombier 		ki.noconf = 1;
148260f7b65SDavid du Colombier 		if(findkey(&s->key, &ki, nil) != RpcOk)
1492ebbfa15SDavid du Colombier 			return failure(fss, nil);
1502ebbfa15SDavid du Colombier 		s->off++;
1512ebbfa15SDavid du Colombier 		priv = s->key->priv;
1522ebbfa15SDavid du Colombier 		*n = snprint(va, *n, "%B", priv->pub.n);
1532ebbfa15SDavid du Colombier 		return RpcOk;
1542ebbfa15SDavid du Colombier 	case CHaveResp:
1552ebbfa15SDavid du Colombier 		*n = snprint(va, *n, "%B", s->resp);
1562ebbfa15SDavid du Colombier 		fss->phase = Established;
1572ebbfa15SDavid du Colombier 		return RpcOk;
158*7f0b57c6SDavid du Colombier 	case SHaveResp:
159*7f0b57c6SDavid du Colombier 		priv = s->key->priv;
160*7f0b57c6SDavid du Colombier 		len = (mpsignif(priv->pub.n)+7)/8;
161*7f0b57c6SDavid du Colombier 		if(len > *n)
162*7f0b57c6SDavid du Colombier 			return failure(fss, "signature buffer too short");
163*7f0b57c6SDavid du Colombier 		m = rsadecrypt(priv, s->digest, nil);
164*7f0b57c6SDavid du Colombier 		r = mptobe(m, (uchar*)va, len, nil);
165*7f0b57c6SDavid du Colombier 		if(r < len){
166*7f0b57c6SDavid du Colombier 			memmove((uchar*)va+len-r, va, r);
167*7f0b57c6SDavid du Colombier 			memset(va, 0, len-r);
168*7f0b57c6SDavid du Colombier 		}
169*7f0b57c6SDavid du Colombier 		*n = len;
170*7f0b57c6SDavid du Colombier 		mpfree(m);
171*7f0b57c6SDavid du Colombier 		fss->phase = Established;
172*7f0b57c6SDavid du Colombier 		return RpcOk;
173*7f0b57c6SDavid du Colombier 	case VHaveResp:
174*7f0b57c6SDavid du Colombier 		*n = snprint(va, *n, "%s", s->sigresp == 0? "ok":
175*7f0b57c6SDavid du Colombier 			"signature does not verify");
176*7f0b57c6SDavid du Colombier 		fss->phase = Established;
177*7f0b57c6SDavid du Colombier 		return RpcOk;
1782ebbfa15SDavid du Colombier 	}
1792ebbfa15SDavid du Colombier }
1802ebbfa15SDavid du Colombier 
1812ebbfa15SDavid du Colombier static int
rsawrite(Fsstate * fss,void * va,uint n)182*7f0b57c6SDavid du Colombier rsawrite(Fsstate *fss, void *va, uint n)
1832ebbfa15SDavid du Colombier {
184*7f0b57c6SDavid du Colombier 	RSApriv *priv;
185*7f0b57c6SDavid du Colombier 	mpint *m, *mm;
1862ebbfa15SDavid du Colombier 	State *s;
187*7f0b57c6SDavid du Colombier 	char *hash;
188*7f0b57c6SDavid du Colombier 	int dlen;
1892ebbfa15SDavid du Colombier 
1902ebbfa15SDavid du Colombier 	s = fss->ps;
1912ebbfa15SDavid du Colombier 	switch(fss->phase){
1922ebbfa15SDavid du Colombier 	default:
1932ebbfa15SDavid du Colombier 		return phaseerror(fss, "write");
1942ebbfa15SDavid du Colombier 	case CHavePub:
1952ebbfa15SDavid du Colombier 		if(s->key == nil)
1962ebbfa15SDavid du Colombier 			return failure(fss, "no current key");
1972ebbfa15SDavid du Colombier 		switch(canusekey(fss, s->key)){
1982ebbfa15SDavid du Colombier 		case -1:
1992ebbfa15SDavid du Colombier 			return RpcConfirm;
2002ebbfa15SDavid du Colombier 		case 0:
2012ebbfa15SDavid du Colombier 			return failure(fss, "confirmation denied");
2022ebbfa15SDavid du Colombier 		case 1:
2032ebbfa15SDavid du Colombier 			break;
2042ebbfa15SDavid du Colombier 		}
2052ebbfa15SDavid du Colombier 		m = strtomp(va, nil, 16, nil);
2066ca1cad2SDavid du Colombier 		if(m == nil)
2076ca1cad2SDavid du Colombier 			return failure(fss, "invalid challenge value");
2082ebbfa15SDavid du Colombier 		m = rsadecrypt(s->key->priv, m, m);
2092ebbfa15SDavid du Colombier 		s->resp = m;
2102ebbfa15SDavid du Colombier 		fss->phase = CHaveResp;
2112ebbfa15SDavid du Colombier 		return RpcOk;
212*7f0b57c6SDavid du Colombier 	case SNeedHash:
213*7f0b57c6SDavid du Colombier 	case VNeedHash:
214*7f0b57c6SDavid du Colombier 		/* get hash type from key */
215*7f0b57c6SDavid du Colombier 		hash = _strfindattr(s->key->attr, "hash");
216*7f0b57c6SDavid du Colombier 		if(hash == nil)
217*7f0b57c6SDavid du Colombier 			hash = "sha1";
218*7f0b57c6SDavid du Colombier 		if(strcmp(hash, "sha1") == 0)
219*7f0b57c6SDavid du Colombier 			dlen = SHA1dlen;
220*7f0b57c6SDavid du Colombier 		else if(strcmp(hash, "md5") == 0)
221*7f0b57c6SDavid du Colombier 			dlen = MD5dlen;
222*7f0b57c6SDavid du Colombier 		else
223*7f0b57c6SDavid du Colombier 			return failure(fss, "unknown hash function %s", hash);
224*7f0b57c6SDavid du Colombier 		if(n != dlen)
225*7f0b57c6SDavid du Colombier 			return failure(fss, "hash length %d should be %d",
226*7f0b57c6SDavid du Colombier 				n, dlen);
227*7f0b57c6SDavid du Colombier 		priv = s->key->priv;
228*7f0b57c6SDavid du Colombier 		s->digest = mkdigest(&priv->pub, hash, (uchar *)va, n);
229*7f0b57c6SDavid du Colombier 		if(s->digest == nil)
230*7f0b57c6SDavid du Colombier 			return failure(fss, nil);
231*7f0b57c6SDavid du Colombier 		if(fss->phase == VNeedHash)
232*7f0b57c6SDavid du Colombier 			fss->phase = VNeedSig;
233*7f0b57c6SDavid du Colombier 		else
234*7f0b57c6SDavid du Colombier 			fss->phase = SHaveResp;
235*7f0b57c6SDavid du Colombier 		return RpcOk;
236*7f0b57c6SDavid du Colombier 	case VNeedSig:
237*7f0b57c6SDavid du Colombier 		priv = s->key->priv;
238*7f0b57c6SDavid du Colombier 		m = betomp((uchar*)va, n, nil);
239*7f0b57c6SDavid du Colombier 		mm = rsaencrypt(&priv->pub, m, nil);
240*7f0b57c6SDavid du Colombier 		s->sigresp = mpcmp(s->digest, mm);
241*7f0b57c6SDavid du Colombier 		mpfree(m);
242*7f0b57c6SDavid du Colombier 		mpfree(mm);
243*7f0b57c6SDavid du Colombier 		fss->phase = VHaveResp;
244*7f0b57c6SDavid du Colombier 		return RpcOk;
2452ebbfa15SDavid du Colombier 	}
2462ebbfa15SDavid du Colombier }
2472ebbfa15SDavid du Colombier 
2482ebbfa15SDavid du Colombier static void
rsaclose(Fsstate * fss)2492ebbfa15SDavid du Colombier rsaclose(Fsstate *fss)
2502ebbfa15SDavid du Colombier {
2512ebbfa15SDavid du Colombier 	State *s;
2522ebbfa15SDavid du Colombier 
2532ebbfa15SDavid du Colombier 	s = fss->ps;
2542ebbfa15SDavid du Colombier 	if(s->key)
2552ebbfa15SDavid du Colombier 		closekey(s->key);
2562ebbfa15SDavid du Colombier 	if(s->resp)
2572ebbfa15SDavid du Colombier 		mpfree(s->resp);
258*7f0b57c6SDavid du Colombier 	if(s->digest)
259*7f0b57c6SDavid du Colombier 		mpfree(s->digest);
2602ebbfa15SDavid du Colombier 	free(s);
2612ebbfa15SDavid du Colombier }
2622ebbfa15SDavid du Colombier 
2632ebbfa15SDavid du Colombier static int
rsaaddkey(Key * k,int before)26470b8e010SDavid du Colombier rsaaddkey(Key *k, int before)
2652ebbfa15SDavid du Colombier {
2662ebbfa15SDavid du Colombier 	fmtinstall('B', mpfmt);
2672ebbfa15SDavid du Colombier 
2682ebbfa15SDavid du Colombier 	if((k->priv = readrsapriv(k)) == nil){
2692ebbfa15SDavid du Colombier 		werrstr("malformed key data");
2702ebbfa15SDavid du Colombier 		return -1;
2712ebbfa15SDavid du Colombier 	}
27270b8e010SDavid du Colombier 	return replacekey(k, before);
2732ebbfa15SDavid du Colombier }
2742ebbfa15SDavid du Colombier 
2752ebbfa15SDavid du Colombier static void
rsaclosekey(Key * k)2762ebbfa15SDavid du Colombier rsaclosekey(Key *k)
2772ebbfa15SDavid du Colombier {
2782ebbfa15SDavid du Colombier 	rsaprivfree(k->priv);
2792ebbfa15SDavid du Colombier }
2802ebbfa15SDavid du Colombier 
2812ebbfa15SDavid du Colombier Proto rsa = {
2822ebbfa15SDavid du Colombier .name=	"rsa",
2832ebbfa15SDavid du Colombier .init=		rsainit,
2842ebbfa15SDavid du Colombier .write=	rsawrite,
2852ebbfa15SDavid du Colombier .read=	rsaread,
2862ebbfa15SDavid du Colombier .close=	rsaclose,
2872ebbfa15SDavid du Colombier .addkey=	rsaaddkey,
2882ebbfa15SDavid du Colombier .closekey=	rsaclosekey,
2892ebbfa15SDavid du Colombier };
290*7f0b57c6SDavid du Colombier 
291*7f0b57c6SDavid du Colombier /*
292*7f0b57c6SDavid du Colombier  * Simple ASN.1 encodings.
293*7f0b57c6SDavid du Colombier  * Lengths < 128 are encoded as 1-bytes constants,
294*7f0b57c6SDavid du Colombier  * making our life easy.
295*7f0b57c6SDavid du Colombier  */
296*7f0b57c6SDavid du Colombier 
297*7f0b57c6SDavid du Colombier /*
298*7f0b57c6SDavid du Colombier  * Hash OIDs
299*7f0b57c6SDavid du Colombier  *
300*7f0b57c6SDavid du Colombier  * SHA1 = 1.3.14.3.2.26
301*7f0b57c6SDavid du Colombier  * MDx = 1.2.840.113549.2.x
302*7f0b57c6SDavid du Colombier  */
303*7f0b57c6SDavid du Colombier #define O0(a,b)	((a)*40+(b))
304*7f0b57c6SDavid du Colombier #define O2(x)	\
305*7f0b57c6SDavid du Colombier 	(((x)>> 7)&0x7F)|0x80, \
306*7f0b57c6SDavid du Colombier 	((x)&0x7F)
307*7f0b57c6SDavid du Colombier #define O3(x)	\
308*7f0b57c6SDavid du Colombier 	(((x)>>14)&0x7F)|0x80, \
309*7f0b57c6SDavid du Colombier 	(((x)>> 7)&0x7F)|0x80, \
310*7f0b57c6SDavid du Colombier 	((x)&0x7F)
311*7f0b57c6SDavid du Colombier uchar oidsha1[] = { O0(1, 3), 14, 3, 2, 26 };
312*7f0b57c6SDavid du Colombier uchar oidmd2[] = { O0(1, 2), O2(840), O3(113549), 2, 2 };
313*7f0b57c6SDavid du Colombier uchar oidmd5[] = { O0(1, 2), O2(840), O3(113549), 2, 5 };
314*7f0b57c6SDavid du Colombier 
315*7f0b57c6SDavid du Colombier /*
316*7f0b57c6SDavid du Colombier  *	DigestInfo ::= SEQUENCE {
317*7f0b57c6SDavid du Colombier  *		digestAlgorithm AlgorithmIdentifier,
318*7f0b57c6SDavid du Colombier  *		digest OCTET STRING
319*7f0b57c6SDavid du Colombier  *	}
320*7f0b57c6SDavid du Colombier  *
321*7f0b57c6SDavid du Colombier  * except that OpenSSL seems to sign
322*7f0b57c6SDavid du Colombier  *
323*7f0b57c6SDavid du Colombier  *	DigestInfo ::= SEQUENCE {
324*7f0b57c6SDavid du Colombier  *		SEQUENCE{ digestAlgorithm AlgorithmIdentifier, NULL }
325*7f0b57c6SDavid du Colombier  *		digest OCTET STRING
326*7f0b57c6SDavid du Colombier  *	}
327*7f0b57c6SDavid du Colombier  *
328*7f0b57c6SDavid du Colombier  * instead.  Sigh.
329*7f0b57c6SDavid du Colombier  */
330*7f0b57c6SDavid du Colombier static int
mkasn1(uchar * asn1,char * alg,uchar * d,uint dlen)331*7f0b57c6SDavid du Colombier mkasn1(uchar *asn1, char *alg, uchar *d, uint dlen)
332*7f0b57c6SDavid du Colombier {
333*7f0b57c6SDavid du Colombier 	uchar *obj, *p;
334*7f0b57c6SDavid du Colombier 	uint olen;
335*7f0b57c6SDavid du Colombier 
336*7f0b57c6SDavid du Colombier 	if(strcmp(alg, "sha1") == 0){
337*7f0b57c6SDavid du Colombier 		obj = oidsha1;
338*7f0b57c6SDavid du Colombier 		olen = sizeof(oidsha1);
339*7f0b57c6SDavid du Colombier 	}else if(strcmp(alg, "md5") == 0){
340*7f0b57c6SDavid du Colombier 		obj = oidmd5;
341*7f0b57c6SDavid du Colombier 		olen = sizeof(oidmd5);
342*7f0b57c6SDavid du Colombier 	}else{
343*7f0b57c6SDavid du Colombier 		sysfatal("bad alg in mkasn1");
344*7f0b57c6SDavid du Colombier 		return -1;
345*7f0b57c6SDavid du Colombier 	}
346*7f0b57c6SDavid du Colombier 
347*7f0b57c6SDavid du Colombier 	p = asn1;
348*7f0b57c6SDavid du Colombier 	*p++ = 0x30;		/* sequence */
349*7f0b57c6SDavid du Colombier 	p++;
350*7f0b57c6SDavid du Colombier 
351*7f0b57c6SDavid du Colombier 	*p++ = 0x30;		/* another sequence */
352*7f0b57c6SDavid du Colombier 	p++;
353*7f0b57c6SDavid du Colombier 
354*7f0b57c6SDavid du Colombier 	*p++ = 0x06;		/* object id */
355*7f0b57c6SDavid du Colombier 	*p++ = olen;
356*7f0b57c6SDavid du Colombier 	memmove(p, obj, olen);
357*7f0b57c6SDavid du Colombier 	p += olen;
358*7f0b57c6SDavid du Colombier 
359*7f0b57c6SDavid du Colombier 	*p++ = 0x05;		/* null */
360*7f0b57c6SDavid du Colombier 	*p++ = 0;
361*7f0b57c6SDavid du Colombier 
362*7f0b57c6SDavid du Colombier 	asn1[3] = p - (asn1+4);	/* end of inner sequence */
363*7f0b57c6SDavid du Colombier 
364*7f0b57c6SDavid du Colombier 	*p++ = 0x04;		/* octet string */
365*7f0b57c6SDavid du Colombier 	*p++ = dlen;
366*7f0b57c6SDavid du Colombier 	memmove(p, d, dlen);
367*7f0b57c6SDavid du Colombier 	p += dlen;
368*7f0b57c6SDavid du Colombier 
369*7f0b57c6SDavid du Colombier 	asn1[1] = p - (asn1+2);	/* end of outer sequence */
370*7f0b57c6SDavid du Colombier 	return p - asn1;
371*7f0b57c6SDavid du Colombier }
372*7f0b57c6SDavid du Colombier 
373*7f0b57c6SDavid du Colombier static mpint*
mkdigest(RSApub * key,char * hashalg,uchar * hash,uint dlen)374*7f0b57c6SDavid du Colombier mkdigest(RSApub *key, char *hashalg, uchar *hash, uint dlen)
375*7f0b57c6SDavid du Colombier {
376*7f0b57c6SDavid du Colombier 	mpint *m;
377*7f0b57c6SDavid du Colombier 	uchar asn1[512], *buf;
378*7f0b57c6SDavid du Colombier 	int len, n, pad;
379*7f0b57c6SDavid du Colombier 
380*7f0b57c6SDavid du Colombier 	/*
381*7f0b57c6SDavid du Colombier 	 * Create ASN.1
382*7f0b57c6SDavid du Colombier 	 */
383*7f0b57c6SDavid du Colombier 	n = mkasn1(asn1, hashalg, hash, dlen);
384*7f0b57c6SDavid du Colombier 
385*7f0b57c6SDavid du Colombier 	/*
386*7f0b57c6SDavid du Colombier 	 * PKCS#1 padding
387*7f0b57c6SDavid du Colombier 	 */
388*7f0b57c6SDavid du Colombier 	len = (mpsignif(key->n)+7)/8 - 1;
389*7f0b57c6SDavid du Colombier 	if(len < n+2){
390*7f0b57c6SDavid du Colombier 		werrstr("rsa key too short");
391*7f0b57c6SDavid du Colombier 		return nil;
392*7f0b57c6SDavid du Colombier 	}
393*7f0b57c6SDavid du Colombier 	pad = len - (n+2);
394*7f0b57c6SDavid du Colombier 	buf = emalloc(len);
395*7f0b57c6SDavid du Colombier 	buf[0] = 0x01;
396*7f0b57c6SDavid du Colombier 	memset(buf+1, 0xFF, pad);
397*7f0b57c6SDavid du Colombier 	buf[1+pad] = 0x00;
398*7f0b57c6SDavid du Colombier 	memmove(buf+1+pad+1, asn1, n);
399*7f0b57c6SDavid du Colombier 	m = betomp(buf, len, nil);
400*7f0b57c6SDavid du Colombier 	free(buf);
401*7f0b57c6SDavid du Colombier 	return m;
402*7f0b57c6SDavid du Colombier }
403