From 6e527fbc4d8f404a7eec934e5c9efaaaa92ffdff Mon Sep 17 00:00:00 2001 From: rsc Date: Sun, 13 Feb 2005 05:59:29 +0000 Subject: new auth --- src/cmd/auth/factotum/pkcs1.c | 154 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/cmd/auth/factotum/pkcs1.c (limited to 'src/cmd/auth/factotum/pkcs1.c') diff --git a/src/cmd/auth/factotum/pkcs1.c b/src/cmd/auth/factotum/pkcs1.c new file mode 100644 index 00000000..fb35ce83 --- /dev/null +++ b/src/cmd/auth/factotum/pkcs1.c @@ -0,0 +1,154 @@ +#include "std.h" +#include "dat.h" + +/* + * PKCS #1 v2.0 signatures (aka RSASSA-PKCS1-V1_5) + * + * You don't want to read the spec. + * Here is what you need to know. + * + * RSA sign (aka RSASP1) is just an RSA encryption. + * RSA verify (aka RSAVP1) is just an RSA decryption. + * + * We sign hashes of messages instead of the messages + * themselves. + * + * The hashes are encoded in ASN.1 DER to identify + * the signature type, and then prefixed with 0x01 PAD 0x00 + * where PAD is as many 0xFF bytes as desired. + */ + +static int mkasn1(uchar *asn1, DigestAlg *alg, uchar *d, uint dlen); + +int +rsasign(RSApriv *key, DigestAlg *hash, uchar *digest, uint dlen, + uchar *sig, uint siglen) +{ + uchar asn1[64], *buf; + int n, len, pad; + mpint *m, *s; + + /* + * Create ASN.1 + */ + n = mkasn1(asn1, hash, digest, dlen); + + /* + * Create number to sign. + */ + len = (mpsignif(key->pub.n)+7)/8; + if(len < n+2){ + werrstr("rsa key too short"); + return -1; + } + pad = len - (n+2); + if(siglen < len){ + werrstr("signature buffer too short"); + return -1; + } + buf = malloc(len); + if(buf == nil) + return -1; + buf[0] = 0x01; + memset(buf+1, 0xFF, pad); + buf[1+pad] = 0x00; + memmove(buf+1+pad+1, asn1, n); + m = betomp(buf, len, nil); + free(buf); + if(m == nil) + return -1; + + /* + * Sign it. + */ + s = rsadecrypt(key, m, nil); + mpfree(m); + if(s == nil) + return -1; + mptoberjust(s, sig, len); + mpfree(s); + return len; +} + +/* + * Mptobe but shift right to fill buffer. + */ +void +mptoberjust(mpint *b, uchar *buf, uint len) +{ + int n; + + n = mptobe(b, buf, len, nil); + assert(n >= 0); + if(n < len){ + len -= n; + memmove(buf+len, buf, n); + memset(buf, 0, len); + } +} + +/* + * Simple ASN.1 encodings. + * Lengths < 128 are encoded as 1-bytes constants, + * making our life easy. + */ + +/* + * Hash OIDs + * + * SHA1 = 1.3.14.3.2.26 + * MDx = 1.2.840.113549.2.x + */ +#define O0(a,b) ((a)*40+(b)) +#define O2(x) \ + (((x)>>7)&0x7F)|0x80, \ + ((x)&0x7F) +#define O3(x) \ + (((x)>>14)&0x7F)|0x80, \ + (((x)>>7)&0x7F)|0x80, \ + ((x)&0x7F) +uchar oidsha1[] = { O0(1, 3), 14, 3, 2, 26 }; +uchar oidmd2[] = { O0(1, 2), O2(840), O3(113549), 2, 2 }; +uchar oidmd5[] = { O0(1, 2), O2(840), O3(113549), 2, 5 }; + +/* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm AlgorithmIdentifier, + * digest OCTET STRING + * } + */ +static int +mkasn1(uchar *asn1, DigestAlg *alg, uchar *d, uint dlen) +{ + uchar *obj, *p; + uint olen; + + if(alg == sha1){ + obj = oidsha1; + olen = sizeof(oidsha1); + }else if(alg == md5){ + obj = oidmd5; + olen = sizeof(oidmd5); + }else{ + sysfatal("bad alg in mkasn1"); + return -1; + } + + p = asn1; + *p++ = 0x30; /* sequence */ + p++; + + *p++ = 0x06; /* object id */ + *p++ = olen; + memmove(p, obj, olen); + p += olen; + + *p++ = 0x04; /* octet string */ + *p++ = dlen; + memmove(p, d, dlen); + p += dlen; + + asn1[1] = p - (asn1+2); + return p-asn1; +} + -- cgit v1.2.3