Blob


1 #include "std.h"
2 #include "dat.h"
4 /*
5 * RSA authentication.
6 *
7 * Encrypt/Decrypt:
8 * start n=xxx ek=xxx
9 * write msg
10 * read encrypt/decrypt(msg)
11 *
12 * Sign (PKCS #1 using hash=sha1 or hash=md5)
13 * start n=xxx ek=xxx
14 * write hash(msg)
15 * read signature(hash(msg))
16 *
17 * Verify:
18 * start n=xxx ek=xxx
19 * write hash(msg)
20 * write signature(hash(msg))
21 * read ok or fail
22 *
23 * all numbers are hexadecimal biginits parsable with strtomp.
24 * must be lower case for attribute matching in start.
25 */
27 static int
28 xrsadecrypt(Conv *c)
29 {
30 char *txt, buf[4096], *role;
31 int n, ret;
32 mpint *m, *mm;
33 Key *k;
34 RSApriv *key;
36 ret = -1;
37 txt = nil;
38 m = nil;
39 mm = nil;
41 /* fetch key */
42 c->state = "keylookup";
43 k = keylookup("%A", c->attr);
44 if(k == nil)
45 goto out;
46 key = k->priv;
48 /* make sure have private half if needed */
49 role = strfindattr(c->attr, "role");
50 if(strcmp(role, "decrypt") == 0 && !key->c2){
51 werrstr("missing private half of key -- cannot decrypt");
52 goto out;
53 }
55 /* read text */
56 c->state = "read";
57 if((n=convreadm(c, &txt)) < 0)
58 goto out;
59 if(n < 32){
60 convprint(c, "data too short");
61 goto out;
62 }
64 /* encrypt/decrypt */
65 m = betomp((uchar*)txt, n, nil);
66 if(m == nil)
67 goto out;
68 if(strcmp(role, "decrypt") == 0)
69 mm = rsadecrypt(key, m, nil);
70 else
71 mm = rsaencrypt(&key->pub, m, nil);
72 if(mm == nil)
73 goto out;
74 n = mptobe(mm, (uchar*)buf, sizeof buf, nil);
76 /* send response */
77 c->state = "write";
78 convwrite(c, buf, n);
79 ret = 0;
81 out:
82 mpfree(m);
83 mpfree(mm);
84 keyclose(k);
85 free(txt);
86 return ret;
87 }
89 static int
90 xrsasign(Conv *c)
91 {
92 char *hash, *role;
93 int dlen, n, ret;
94 DigestAlg *hashfn;
95 Key *k;
96 RSApriv *key;
97 uchar sig[1024], digest[64];
98 char *sig2;
100 ret = -1;
102 /* fetch key */
103 c->state = "keylookup";
104 k = keylookup("%A", c->attr);
105 if(k == nil)
106 goto out;
108 /* make sure have private half if needed */
109 key = k->priv;
110 role = strfindattr(c->attr, "role");
111 if(strcmp(role, "sign") == 0 && !key->c2){
112 werrstr("missing private half of key -- cannot sign");
113 goto out;
116 /* get hash type from key */
117 hash = strfindattr(k->attr, "hash");
118 if(hash == nil)
119 hash = "sha1";
120 if(strcmp(hash, "sha1") == 0){
121 hashfn = sha1;
122 dlen = SHA1dlen;
123 }else if(strcmp(hash, "md5") == 0){
124 hashfn = md5;
125 dlen = MD5dlen;
126 }else{
127 werrstr("unknown hash function %s", hash);
128 goto out;
131 /* read hash */
132 c->state = "read hash";
133 if((n=convread(c, digest, dlen)) < 0)
134 goto out;
136 if(strcmp(role, "sign") == 0){
137 /* sign */
138 if((n=rsasign(key, hashfn, digest, dlen, sig, sizeof sig)) < 0)
139 goto out;
141 /* write */
142 convwrite(c, sig, n);
143 }else{
144 /* read signature */
145 if((n = convreadm(c, &sig2)) < 0)
146 goto out;
148 /* verify */
149 if(rsaverify(&key->pub, hashfn, digest, dlen, (uchar*)sig2, n) == 0)
150 convprint(c, "ok");
151 else
152 convprint(c, "signature does not verify");
153 free(sig2);
155 ret = 0;
157 out:
158 keyclose(k);
159 return ret;
162 /*
163 * convert to canonical form (lower case)
164 * for use in attribute matches.
165 */
166 static void
167 strlwr(char *a)
169 for(; *a; a++){
170 if('A' <= *a && *a <= 'Z')
171 *a += 'a' - 'A';
175 static RSApriv*
176 readrsapriv(Key *k)
178 char *a;
179 RSApriv *priv;
181 priv = rsaprivalloc();
183 if((a=strfindattr(k->attr, "ek"))==nil
184 || (priv->pub.ek=strtomp(a, nil, 16, nil))==nil)
185 goto Error;
186 strlwr(a);
187 if((a=strfindattr(k->attr, "n"))==nil
188 || (priv->pub.n=strtomp(a, nil, 16, nil))==nil)
189 goto Error;
190 strlwr(a);
191 if(k->privattr == nil) /* only public half */
192 return priv;
194 if((a=strfindattr(k->privattr, "!p"))==nil
195 || (priv->p=strtomp(a, nil, 16, nil))==nil)
196 goto Error;
197 strlwr(a);
198 if((a=strfindattr(k->privattr, "!q"))==nil
199 || (priv->q=strtomp(a, nil, 16, nil))==nil)
200 goto Error;
201 strlwr(a);
202 if(!probably_prime(priv->p, 20) || !probably_prime(priv->q, 20)) {
203 werrstr("rsa: p or q not prime");
204 goto Error;
206 if((a=strfindattr(k->privattr, "!kp"))==nil
207 || (priv->kp=strtomp(a, nil, 16, nil))==nil)
208 goto Error;
209 strlwr(a);
210 if((a=strfindattr(k->privattr, "!kq"))==nil
211 || (priv->kq=strtomp(a, nil, 16, nil))==nil)
212 goto Error;
213 strlwr(a);
214 if((a=strfindattr(k->privattr, "!c2"))==nil
215 || (priv->c2=strtomp(a, nil, 16, nil))==nil)
216 goto Error;
217 strlwr(a);
218 if((a=strfindattr(k->privattr, "!dk"))==nil
219 || (priv->dk=strtomp(a, nil, 16, nil))==nil)
220 goto Error;
221 strlwr(a);
222 return priv;
224 Error:
225 rsaprivfree(priv);
226 return nil;
229 static int
230 rsacheck(Key *k)
232 static int first = 1;
234 if(first){
235 fmtinstall('B', mpfmt);
236 first = 0;
239 if((k->priv = readrsapriv(k)) == nil){
240 werrstr("malformed key data");
241 return -1;
243 return 0;
246 static void
247 rsaclose(Key *k)
249 rsaprivfree(k->priv);
250 k->priv = nil;
253 static Role
254 rsaroles[] =
256 "sign", xrsasign,
257 "verify", xrsasign, /* public operation */
258 "decrypt", xrsadecrypt,
259 "encrypt", xrsadecrypt, /* public operation */
261 };
263 Proto rsa = {
264 "rsa",
265 rsaroles,
266 nil,
267 rsacheck,
268 rsaclose
269 };