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