Browse Source

Plan 9 from Bell Labs 2008-03-25

David du Colombier 16 years ago
parent
commit
1cbb667e61

+ 5 - 1
dist/replica/_plan9.db

@@ -10021,7 +10021,7 @@ sys/src/cmd/cdfs - 20000000775 sys sys 1039727558 0
 sys/src/cmd/cdfs/buf.c - 664 sys sys 1205271166 1923
 sys/src/cmd/cdfs/dat.h - 664 sys sys 1206046829 4619
 sys/src/cmd/cdfs/fns.h - 664 sys sys 969542122 297
-sys/src/cmd/cdfs/main.c - 664 sys sys 1206142363 12381
+sys/src/cmd/cdfs/main.c - 664 sys sys 1206379554 12449
 sys/src/cmd/cdfs/mkfile - 664 sys sys 1204937991 153
 sys/src/cmd/cdfs/mmc.c - 664 sys sys 1206142343 31376
 sys/src/cmd/cec - 20000000775 sys sys 1193683647 0
@@ -15873,3 +15873,7 @@ usr/glenda/lib/profile - 664 glenda glenda 1105128663 890
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
+sys/include/libsec.h - 664 sys sys 1206418956 8792
+sys/src/libmp/port/crttest.c - 664 sys sys 1206419360 812
+sys/src/libsec/port/tlshand.c - 664 sys sys 1206417844 54865
+sys/src/libsec/port/x509.c - 664 sys sys 1206417886 52016

+ 5 - 5
dist/replica/plan9.db

@@ -6109,7 +6109,7 @@ sys/include/httpd.h - 664 sys sys 1190835025 5800
 sys/include/ip.h - 664 sys sys 1204230308 4401
 sys/include/keyboard.h - 664 sys sys 1131637696 865
 sys/include/libc.h - 664 sys sys 1168306860 19851
-sys/include/libsec.h - 664 sys sys 1188328413 8684
+sys/include/libsec.h - 664 sys sys 1206418956 8792
 sys/include/mach.h - 664 sys sys 1178892102 8758
 sys/include/memdraw.h - 664 sys sys 1091904419 5645
 sys/include/memlayer.h - 664 sys sys 1051031022 1851
@@ -10021,7 +10021,7 @@ sys/src/cmd/cdfs - 20000000775 sys sys 1039727558 0
 sys/src/cmd/cdfs/buf.c - 664 sys sys 1205271166 1923
 sys/src/cmd/cdfs/dat.h - 664 sys sys 1206046829 4619
 sys/src/cmd/cdfs/fns.h - 664 sys sys 969542122 297
-sys/src/cmd/cdfs/main.c - 664 sys sys 1206142363 12381
+sys/src/cmd/cdfs/main.c - 664 sys sys 1206379554 12449
 sys/src/cmd/cdfs/mkfile - 664 sys sys 1204937991 153
 sys/src/cmd/cdfs/mmc.c - 664 sys sys 1206142343 31376
 sys/src/cmd/cec - 20000000775 sys sys 1193683647 0
@@ -15517,7 +15517,7 @@ sys/src/libmp/mkfile - 664 sys sys 1134426476 962
 sys/src/libmp/port - 20000000775 sys sys 1084469736 0
 sys/src/libmp/port/betomp.c - 664 sys sys 1127128751 617
 sys/src/libmp/port/crt.c - 664 sys sys 1014930532 2050
-sys/src/libmp/port/crttest.c - 664 sys sys 956279160 813
+sys/src/libmp/port/crttest.c - 664 sys sys 1206419360 812
 sys/src/libmp/port/dat.h - 664 sys sys 1045502198 350
 sys/src/libmp/port/letomp.c - 664 sys sys 1055700222 432
 sys/src/libmp/port/mkfile - 664 sys sys 1085667604 620
@@ -15698,8 +15698,8 @@ sys/src/libsec/port/sha1pickle.c - 664 sys sys 988225292 717
 sys/src/libsec/port/smallprimes.c - 664 sys sys 984710525 6851
 sys/src/libsec/port/smallprimetest.c - 664 sys sys 984710525 70640
 sys/src/libsec/port/thumb.c - 664 sys sys 1019832052 1891
-sys/src/libsec/port/tlshand.c - 664 sys sys 1126971523 54895
-sys/src/libsec/port/x509.c - 664 sys sys 1161441337 50831
+sys/src/libsec/port/tlshand.c - 664 sys sys 1206417844 54865
+sys/src/libsec/port/x509.c - 664 sys sys 1206417886 52016
 sys/src/libsec/power - 20000000775 sys sys 1039727694 0
 sys/src/libsec/power/mkfile - 664 sys sys 1032061453 139
 sys/src/libstdio - 20000000775 sys sys 1055700384 0

+ 5 - 0
dist/replica/plan9.log

@@ -18862,3 +18862,8 @@
 1206318605 9 c sys/src/9/port/portclock.c - 664 sys sys 1206317920 4274
 1206318605 10 c sys/src/9/port/portdat.h - 664 sys sys 1206317920 22759
 1206318605 11 c sys/src/9/port/portfns.h - 664 sys sys 1206317920 11095
+1206379805 0 c sys/src/cmd/cdfs/main.c - 664 sys sys 1206379554 12449
+1206419404 0 c sys/include/libsec.h - 664 sys sys 1206418956 8792
+1206419404 1 c sys/src/libmp/port/crttest.c - 664 sys sys 1206419360 812
+1206419404 2 c sys/src/libsec/port/tlshand.c - 664 sys sys 1206417844 54865
+1206419404 3 c sys/src/libsec/port/x509.c - 664 sys sys 1206417886 52016

+ 6 - 2
sys/include/libsec.h

@@ -1,6 +1,7 @@
 #pragma	lib	"libsec.a"
 #pragma	src	"/sys/src/libsec"
 
+
 #ifndef _MPINT
 typedef struct mpint mpint;
 #endif
@@ -22,10 +23,12 @@ struct AESstate
 	ulong	setup;
 	int	rounds;
 	int	keybytes;
+//	uint	ctrsz;
 	uchar	key[AESmaxkey];			/* unexpanded key */
-	u32int	ekey[4*(AESmaxrounds + 1)];	/* encryption key */
-	u32int	dkey[4*(AESmaxrounds + 1)];	/* decryption key */
+	ulong	ekey[4*(AESmaxrounds + 1)];	/* encryption key */
+	ulong	dkey[4*(AESmaxrounds + 1)];	/* decryption key */
 	uchar	ivec[AESbsize];			/* initialization vector */
+//	uchar	mackey[3 * AESbsize];		/* 3 XCBC mac 96 keys */
 };
 
 void	setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec);
@@ -333,6 +336,7 @@ void		dsaprivfree(DSApriv*);
 DSAsig*		dsasigalloc(void);
 void		dsasigfree(DSAsig*);
 DSApub*		dsaprivtopub(DSApriv*);
+DSApriv*	asn1toDSApriv(uchar*, int);
 
 /*
  * TLS

+ 70 - 0
sys/src/cmd/auth/asn12dsa.c

@@ -0,0 +1,70 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mp.h>
+#include <libsec.h>
+
+void
+usage(void)
+{
+	fprint(2, "auth/asn12dsa [-t tag] [file]\n");
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	char *s;
+	uchar *buf;
+	int fd;
+	long n, tot;
+	char *tag, *file;
+	DSApriv *key;
+
+	fmtinstall('B', mpfmt);
+
+	tag = nil;
+	ARGBEGIN{
+	case 't':
+		tag = EARGF(usage());
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc != 0 && argc != 1)
+		usage();
+
+	if(argc == 1)
+		file = argv[0];
+	else
+		file = "/dev/stdin";
+
+	if((fd = open(file, OREAD)) < 0)
+		sysfatal("open %s: %r", file);
+	buf = nil;
+	tot = 0;
+	for(;;){
+		buf = realloc(buf, tot+8192);
+		if(buf == nil)
+			sysfatal("realloc: %r");
+		if((n = read(fd, buf+tot, 8192)) < 0)
+			sysfatal("read: %r");
+		if(n == 0)
+			break;
+		tot += n;
+	}
+
+	key = asn1toDSApriv(buf, tot);
+	if(key == nil)
+		sysfatal("couldn't parse asn1 key");
+
+	s = smprint("key proto=dsa %s%sp=%B q=%B alpha=%B key=%B !secret=%B\n",
+		tag ? tag : "", tag ? " " : "",
+		key->pub.p, key->pub.q, key->pub.alpha, key->pub.key,
+		key->secret);
+	if(s == nil)
+		sysfatal("smprint: %r");
+	write(1, s, strlen(s));
+	exits(0);
+}

+ 44 - 0
sys/src/cmd/auth/dsa2pub.c

@@ -0,0 +1,44 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <mp.h>
+#include <libsec.h>
+#include "rsa2any.h"
+
+void
+usage(void)
+{
+	fprint(2, "usage: auth/dsa2pub [file]\n");
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	DSApriv *key;
+	Attr *a;
+	char *s;
+
+	fmtinstall('A', _attrfmt);
+	fmtinstall('B', mpfmt);
+	quotefmtinstall();
+
+	ARGBEGIN{
+	default:
+		usage();
+	}ARGEND
+
+	if(argc > 1)
+		usage();
+
+	if((key = getdsakey(argc, argv, 0, &a)) == nil)
+		sysfatal("%r");
+
+	s = smprint("key %A p=%B q=%B alpha=%B key=%B\n",
+		a, 
+		key->pub.p, key->pub.q, key->pub.alpha, key->pub.key);
+	if(s == nil)
+		sysfatal("smprint: %r");
+	write(1, s, strlen(s));
+	exits(nil);
+}

+ 48 - 0
sys/src/cmd/auth/dsa2ssh.c

@@ -0,0 +1,48 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <mp.h>
+#include <libsec.h>
+#include "rsa2any.h"
+
+void
+usage(void)
+{
+	fprint(2, "usage: auth/dsa2ssh [-c comment] [file]\n");
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	DSApriv *k;
+	char *comment;
+	uchar buf[8192], *p;
+	
+	fmtinstall('B', mpfmt);
+	fmtinstall('[', encodefmt);
+	comment = "";
+	ARGBEGIN{
+	case 'c':
+		comment = EARGF(usage());
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc > 1)
+		usage();
+
+	if((k = getdsakey(argc, argv, 0, nil)) == nil)
+		sysfatal("%r");
+
+	p = buf;
+	p = put4(p, 7);
+	p = putn(p, "ssh-dss", 7);
+	p = putmp2(p, k->pub.p);
+	p = putmp2(p, k->pub.q);
+	p = putmp2(p, k->pub.alpha);
+	p = putmp2(p, k->pub.key);
+	print("ssh-dss %.*[ %s\n", (int)(p - buf), buf, comment);
+	exits(nil);
+}

+ 46 - 0
sys/src/cmd/auth/dsagen.c

@@ -0,0 +1,46 @@
+#include <u.h>
+#include <libc.h>
+#include <mp.h>
+#include <libsec.h>
+
+void
+usage(void)
+{
+	fprint(2, "usage: auth/dsagen [-t 'attr=value attr=value ...']\n");
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	char *s, *tag;
+	DSApriv *key;
+
+	tag = nil;
+	fmtinstall('B', mpfmt);
+
+	ARGBEGIN{
+	case 't':
+		tag = EARGF(usage());
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc != 0)
+		usage();
+
+	key = dsagen(nil);
+
+	s = smprint("key proto=dsa %s%sp=%B q=%B alpha=%B key=%B !secret=%B\n",
+		tag ? tag : "", tag ? " " : "",
+		key->pub.p, key->pub.q, key->pub.alpha, key->pub.key,
+		key->secret);
+	if(s == nil)
+		sysfatal("smprint: %r");
+
+	if(write(1, s, strlen(s)) != strlen(s))
+		sysfatal("write: %r");
+	
+	exits(nil);
+}

+ 8 - 3
sys/src/cmd/auth/mkfile

@@ -3,13 +3,17 @@
 #		programs
 #
 TARG=\
+	asn12dsa\
 	asn12rsa\
 	authsrv\
 	changeuser\
-	convkeys\
 	convkeys2\
+	convkeys\
 	cron\
 	debug\
+	dsa2pub\
+	dsa2ssh\
+	dsagen\
 	guard.srv\
 	keyfs\
 	login\
@@ -20,12 +24,12 @@ TARG=\
 	pemdecode\
 	pemencode\
 	printnetkey\
-	rsagen\
-	rsafill\
 	rsa2csr\
 	rsa2pub\
 	rsa2ssh\
 	rsa2x509\
+	rsafill\
+	rsagen\
 	uniq\
 	warning\
 	wrkey\
@@ -110,6 +114,7 @@ nuke:V:
 	rm -f *.[$OS] *.[$OS].a [$OS].* y.tab.? y.debug y.output $TARG *.acid
 
 $O.%: lib.$O.a
+$O.dsa2ssh $O.dsafill $O.dsa2x509 $O.dsa2pub $O.dsa2csr: rsa2any.$O
 $O.rsa2ssh $O.rsafill $O.rsa2x509 $O.rsa2pub $O.rsa2csr: rsa2any.$O
 $O.authsrv $O.guard.srv: secureidcheck.$O
 

+ 150 - 9
sys/src/cmd/auth/rsa2any.c

@@ -70,11 +70,11 @@ getkey(int argc, char **argv, int needprivate, Attr **pa)
 		return nil;
 	}
 	if((p = _strfindattr(a, "size")) == nil)
-		fprint(2, "rsa2any: warning: missing size; will add\n");
+		fprint(2, "warning: missing size; will add\n");
 	else if((sz = strtol(p, &p, 10)) == 0 || *p != 0)
-		fprint(2, "rsa2any: warning: bad size; will correct\n");
+		fprint(2, "warning: bad size; will correct\n");
 	else if(sz != mpsignif(key->pub.n))
-		fprint(2, "rsa2any: warning: wrong size (got %d, expected %d); will correct\n",
+		fprint(2, "warning: wrong size (got %d, expected %d); will correct\n",
 			sz, mpsignif(key->pub.n));
 	if(!needprivate)
 		goto call;
@@ -103,32 +103,32 @@ getkey(int argc, char **argv, int needprivate, Attr **pa)
 		return nil;
 	}
 	if((p = _strfindattr(a, "!kp")) == nil){
-		fprint(2, "rsa2any: warning: no !kp\n");
+		fprint(2, "warning: no !kp\n");
 		regen = 1;
 		goto regen;
 	}
 	if((key->kp = strtomp(p, &p, 16, nil)) == nil || *p != 0){
-		fprint(2, "rsa2any: warning: bad !kp\n");
+		fprint(2, "warning: bad !kp\n");
 		regen = 1;	
 		goto regen;
 	}
 	if((p = _strfindattr(a, "!kq")) == nil){
-		fprint(2, "rsa2any: warning: no !kq\n");
+		fprint(2, "warning: no !kq\n");
 		regen = 1;	
 		goto regen;
 	}
 	if((key->kq = strtomp(p, &p, 16, nil)) == nil || *p != 0){
-		fprint(2, "rsa2any: warning: bad !kq\n");
+		fprint(2, "warning: bad !kq\n");
 		regen = 1;	
 		goto regen;
 	}
 	if((p = _strfindattr(a, "!c2")) == nil){
-		fprint(2, "rsa2any: warning: no !c2\n");
+		fprint(2, "warning: no !c2\n");
 		regen = 1;	
 		goto regen;
 	}
 	if((key->c2 = strtomp(p, &p, 16, nil)) == nil || *p != 0){
-		fprint(2, "rsa2any: warning: bad !c2\n");
+		fprint(2, "warning: bad !c2\n");
 		regen = 1;	
 		goto regen;
 	}
@@ -158,3 +158,144 @@ call:
 	return key;
 }
 
+DSApriv*
+getdsakey(int argc, char **argv, int needprivate, Attr **pa)
+{
+	char *file, *s, *p;
+	DSApriv *key;
+	Biobuf *b;
+	Attr *a;
+
+	if(argc == 0)
+		file = "#d/0";
+	else
+		file = argv[0];
+
+	key = mallocz(sizeof(RSApriv), 1);
+	if(key == nil)
+		return nil;
+
+	if((b = Bopen(file, OREAD)) == nil){
+		werrstr("open %s: %r", file);
+		return nil;
+	}
+	s = Brdstr(b, '\n', 1);
+	if(s == nil){
+		werrstr("read %s: %r", file);
+		return nil;
+	}
+	if(strncmp(s, "key ", 4) != 0){
+		werrstr("bad key format");
+		return nil;
+	}
+
+	a = _parseattr(s+4);
+	if(a == nil){
+		werrstr("empty key");
+		return nil;
+	}
+	if((p = _strfindattr(a, "proto")) == nil){
+		werrstr("no proto");
+		return nil;
+	}
+	if(strcmp(p, "dsa") != 0){
+		werrstr("proto not dsa");
+		return nil;
+	}
+	if((p = _strfindattr(a, "p")) == nil){
+		werrstr("no p");
+		return nil;
+	}
+	if((key->pub.p = strtomp(p, &p, 16, nil)) == nil || *p != 0){
+		werrstr("bad p");
+		return nil;
+	}
+	if((p = _strfindattr(a, "q")) == nil){
+		werrstr("no q");
+		return nil;
+	}
+	if((key->pub.q = strtomp(p, &p, 16, nil)) == nil || *p != 0){
+		werrstr("bad q");
+		return nil;
+	}
+	if((p = _strfindattr(a, "alpha")) == nil){
+		werrstr("no alpha");
+		return nil;
+	}
+	if((key->pub.alpha = strtomp(p, &p, 16, nil)) == nil || *p != 0){
+		werrstr("bad alpha");
+		return nil;
+	}
+	if((p = _strfindattr(a, "key")) == nil){
+		werrstr("no key=");
+		return nil;
+	}
+	if((key->pub.key = strtomp(p, &p, 16, nil)) == nil || *p != 0){
+		werrstr("bad key=");
+		return nil;
+	}
+	if(!needprivate)
+		goto call;
+	if((p = _strfindattr(a, "!secret")) == nil){
+		werrstr("no !secret");
+		return nil;
+	}
+	if((key->secret = strtomp(p, &p, 16, nil)) == nil || *p != 0){
+		werrstr("bad !secret");
+		return nil;
+	}
+call:
+	a = _delattr(a, "p");
+	a = _delattr(a, "q");
+	a = _delattr(a, "alpha");
+	a = _delattr(a, "key");
+	a = _delattr(a, "!secret");
+	if(pa)
+		*pa = a;
+	return key;
+}
+
+uchar*
+put4(uchar *p, uint n)
+{
+	p[0] = (n>>24)&0xFF;
+	p[1] = (n>>16)&0xFF;
+	p[2] = (n>>8)&0xFF;
+	p[3] = n&0xFF;
+	return p+4;
+}
+
+uchar*
+putn(uchar *p, void *v, uint n)
+{
+	memmove(p, v, n);
+	p += n;
+	return p;
+}
+
+uchar*
+putstr(uchar *p, char *s)
+{
+	p = put4(p, strlen(s));
+	p = putn(p, s, strlen(s));
+	return p;
+}
+
+uchar*
+putmp2(uchar *p, mpint *b)
+{
+	int bits, n;
+	
+	if(mpcmp(b, mpzero) == 0)
+		return put4(p, 0);
+	bits = mpsignif(b);
+	n = (bits+7)/8;
+	if(bits%8 == 0){
+		p = put4(p, n+1);
+		*p++ = 0;
+	}else
+		p = put4(p, n);
+	mptobe(b, p, n, nil);
+	p += n;
+	return p;
+}

+ 6 - 1
sys/src/cmd/auth/rsa2any.h

@@ -1 +1,6 @@
-RSApriv *getkey(int, char**, int, Attr**);
+DSApriv*getdsakey(int argc, char **argv, int needprivate, Attr **pa);
+RSApriv*getkey(int argc, char **argv, int needprivate, Attr **pa);
+uchar*	put4(uchar *p, uint n);
+uchar*	putmp2(uchar *p, mpint *b);
+uchar*	putn(uchar *p, void *v, uint n);
+uchar*	putstr(uchar *p, char *s);

+ 2 - 1
sys/src/cmd/cdfs/main.c

@@ -204,6 +204,7 @@ fsremove(Req *r)
 	}
 }
 
+/* result is one word, so it can be used as a uid in Dir structs */
 static char *
 disctype(Drive *drive)
 {
@@ -221,7 +222,7 @@ disctype(Drive *drive)
 		type = "bd-";
 		break;
 	case Mmcnone:
-		type = "no disc";
+		type = "no-disc";
 		break;
 	default:
 		type = "**GOK**";		/* traditional */

+ 1 - 1
sys/src/libmp/port/crttest.c

@@ -10,7 +10,7 @@ testcrt(mpint **p)
 	mpint *m, *x, *y;
 	int i;
 
-	fmtinstall('B', mpconv);
+	fmtinstall('B', mpfmt);
 
 	// get a modulus and a test number
 	m = mpnew(1024+160);

+ 1 - 2
sys/src/libsec/port/tlshand.c

@@ -2251,8 +2251,7 @@ get16(uchar *p)
 	return (p[0]<<8)|p[1];
 }
 
-/* ANSI offsetof() */
-#define OFFSET(x, s) ((int)(&(((s*)0)->x)))
+#define OFFSET(x, s) offsetof(s, x)
 
 /*
  * malloc and return a new Bytes structure capable of

+ 78 - 4
sys/src/libsec/port/x509.c

@@ -577,7 +577,7 @@ int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint)
 			err = ASN_ETOOBIG;
 		else {
 			if(!unsgned && count > 0 && count < 4 && (*p&0x80))
-				num = -1;		// set all bits, initially
+				num = -1;	/* set all bits, initially */
 			while(count--)
 				num = (num << 8)|(*p++);
 		}
@@ -1852,7 +1852,7 @@ decode_rsapubkey(Bytes* a)
 		goto errret;
 	if(!is_seq(&e, &el) || elistlen(el) != 2)
 		goto errret;
-	
+
 	l = el;
 
 	key->n = mp = asn1mpint(&el->hd);
@@ -1949,6 +1949,68 @@ errret:
 	return nil;
 }
 
+/*
+ * 	DSAPrivateKey ::= SEQUENCE{
+ *		version Version,
+ *		p INTEGER,
+ *		q INTEGER,
+ *		g INTEGER, -- alpha
+ *		pub_key INTEGER, -- key
+ *		priv_key INTEGER, -- secret
+ *	}
+ */
+static DSApriv*
+decode_dsaprivkey(Bytes* a)
+{
+	int version;
+	Elem e;
+	Elist *el;
+	mpint *mp;
+	DSApriv* key;
+
+	key = dsaprivalloc();
+	if(decode(a->data, a->len, &e) != ASN_OK)
+		goto errret;
+	if(!is_seq(&e, &el) || elistlen(el) != 6)
+		goto errret;
+version = -1;
+	if(!is_int(&el->hd, &version) || version != 0)
+{
+fprint(2, "version %d\n", version);
+		goto errret;
+}
+
+	el = el->tl;
+	key->pub.p = mp = asn1mpint(&el->hd);
+	if(mp == nil)
+		goto errret;
+
+	el = el->tl;
+	key->pub.q = mp = asn1mpint(&el->hd);
+	if(mp == nil)
+		goto errret;
+
+	el = el->tl;
+	key->pub.alpha = mp = asn1mpint(&el->hd);
+	if(mp == nil)
+		goto errret;
+
+	el = el->tl;
+	key->pub.key = mp = asn1mpint(&el->hd);
+	if(mp == nil)
+		goto errret;
+
+	el = el->tl;
+	key->secret = mp = asn1mpint(&el->hd);
+	if(mp == nil)
+		goto errret;
+
+	return key;
+errret:
+	dsaprivfree(key);
+	return nil;
+}
+
 static mpint*
 asn1mpint(Elem *e)
 {
@@ -1999,6 +2061,18 @@ asn1toRSApriv(uchar *kd, int kn)
 	return key;
 }
 
+DSApriv*
+asn1toDSApriv(uchar *kd, int kn)
+{
+	Bytes *b;
+	DSApriv *key;
+
+	b = makebytes(kd, kn);
+	key = decode_dsaprivkey(b);
+	freebytes(b);
+	return key;
+}
+
 /*
  * digest(CertificateInfo)
  * Our ASN.1 library doesn't return pointers into the original
@@ -2084,7 +2158,7 @@ end:
 		free(pkcs1buf);
 	return err;
 }
-	
+
 RSApub*
 X509toRSApub(uchar *cert, int ncert, char *name, int nname)
 {
@@ -2101,7 +2175,7 @@ X509toRSApub(uchar *cert, int ncert, char *name, int nname)
 	if(name != nil && c->subject != nil){
 		e = strchr(c->subject, ',');
 		if(e != nil)
-			*e = 0;  // take just CN part of Distinguished Name
+			*e = 0;	/* take just CN part of Distinguished Name */
 		strncpy(name, c->subject, nname);
 	}
 	pk = decode_rsapubkey(c->publickey);