plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

pkcs1.c (3693B)


      1 #include "std.h"
      2 #include "dat.h"
      3 
      4 /*
      5  * PKCS #1 v2.0 signatures (aka RSASSA-PKCS1-V1_5)
      6  *
      7  * You don't want to read the spec.
      8  * Here is what you need to know.
      9  *
     10  * RSA sign (aka RSASP1) is just an RSA encryption.
     11  * RSA verify (aka RSAVP1) is just an RSA decryption.
     12  *
     13  * We sign hashes of messages instead of the messages
     14  * themselves.
     15  *
     16  * The hashes are encoded in ASN.1 DER to identify
     17  * the signature type, and then prefixed with 0x01 PAD 0x00
     18  * where PAD is as many 0xFF bytes as desired.
     19  */
     20 
     21 static int mkasn1(uchar *asn1, DigestAlg *alg, uchar *d, uint dlen);
     22 
     23 int
     24 rsasign(RSApriv *key, DigestAlg *hash, uchar *digest, uint dlen,
     25 	uchar *sig, uint siglen)
     26 {
     27 	uchar asn1[64], *buf;
     28 	int n, len, pad;
     29 	mpint *m, *s;
     30 
     31 	/*
     32 	 * Create ASN.1
     33 	 */
     34 	n = mkasn1(asn1, hash, digest, dlen);
     35 
     36 	/*
     37 	 * Create number to sign.
     38 	 */
     39 	len = (mpsignif(key->pub.n)+7)/8 - 1;
     40 	if(len < n+2){
     41 		werrstr("rsa key too short");
     42 		return -1;
     43 	}
     44 	pad = len - (n+2);
     45 	if(siglen < len){
     46 		werrstr("signature buffer too short");
     47 		return -1;
     48 	}
     49 	buf = malloc(len);
     50 	if(buf == nil)
     51 		return -1;
     52 	buf[0] = 0x01;
     53 	memset(buf+1, 0xFF, pad);
     54 	buf[1+pad] = 0x00;
     55 	memmove(buf+1+pad+1, asn1, n);
     56 	m = betomp(buf, len, nil);
     57 	free(buf);
     58 	if(m == nil)
     59 		return -1;
     60 
     61 	/*
     62 	 * Sign it.
     63 	 */
     64 	s = rsadecrypt(key, m, nil);
     65 	mpfree(m);
     66 	if(s == nil)
     67 		return -1;
     68 	mptoberjust(s, sig, len+1);
     69 	mpfree(s);
     70 	return len+1;
     71 }
     72 
     73 int
     74 rsaverify(RSApub *key, DigestAlg *hash, uchar *digest, uint dlen,
     75 	uchar *sig, uint siglen)
     76 {
     77 	uchar asn1[64], xasn1[64];
     78 	int n, nn;
     79 	mpint *m, *s;
     80 
     81 	/*
     82 	 * Create ASN.1
     83 	 */
     84 	n = mkasn1(asn1, hash, digest, dlen);
     85 
     86 	/*
     87 	 * Extract plaintext of signature.
     88 	 */
     89 	s = betomp(sig, siglen, nil);
     90 	if(s == nil)
     91 		return -1;
     92 	m = rsaencrypt(key, s, nil);
     93 	mpfree(s);
     94 	if(m == nil)
     95 		return -1;
     96 	nn = mptobe(m, xasn1, sizeof xasn1, nil);
     97 	mpfree(m);
     98 	if(n != nn || memcmp(asn1, xasn1, n) != 0){
     99 		werrstr("signature did not verify");
    100 		return -1;
    101 	}
    102 	return 0;
    103 }
    104 
    105 /*
    106  * Mptobe but shift right to fill buffer.
    107  */
    108 void
    109 mptoberjust(mpint *b, uchar *buf, uint len)
    110 {
    111 	int n;
    112 
    113 	n = mptobe(b, buf, len, nil);
    114 	assert(n >= 0);
    115 	if(n < len){
    116 		len -= n;
    117 		memmove(buf+len, buf, n);
    118 		memset(buf, 0, len);
    119 	}
    120 }
    121 
    122 /*
    123  * Simple ASN.1 encodings.
    124  * Lengths < 128 are encoded as 1-bytes constants,
    125  * making our life easy.
    126  */
    127 
    128 /*
    129  * Hash OIDs
    130  *
    131  * SHA1 = 1.3.14.3.2.26
    132  * MDx = 1.2.840.113549.2.x
    133  */
    134 #define O0(a,b)	((a)*40+(b))
    135 #define O2(x)	\
    136 	(((x)>>7)&0x7F)|0x80, \
    137 	((x)&0x7F)
    138 #define O3(x)	\
    139 	(((x)>>14)&0x7F)|0x80, \
    140 	(((x)>>7)&0x7F)|0x80, \
    141 	((x)&0x7F)
    142 uchar oidsha1[] = { O0(1, 3), 14, 3, 2, 26 };
    143 uchar oidmd2[] = { O0(1, 2), O2(840), O3(113549), 2, 2 };
    144 uchar oidmd5[] = { O0(1, 2), O2(840), O3(113549), 2, 5 };
    145 
    146 /*
    147  *	DigestInfo ::= SEQUENCE {
    148  *		digestAlgorithm AlgorithmIdentifier,
    149  *		digest OCTET STRING
    150  *	}
    151  *
    152  * except that OpenSSL seems to sign
    153  *
    154  *	DigestInfo ::= SEQUENCE {
    155  *		SEQUENCE{ digestAlgorithm AlgorithmIdentifier, NULL }
    156  *		digest OCTET STRING
    157  *	}
    158  *
    159  * instead.  Sigh.
    160  */
    161 static int
    162 mkasn1(uchar *asn1, DigestAlg *alg, uchar *d, uint dlen)
    163 {
    164 	uchar *obj, *p;
    165 	uint olen;
    166 
    167 	if(alg == sha1){
    168 		obj = oidsha1;
    169 		olen = sizeof(oidsha1);
    170 	}else if(alg == md5){
    171 		obj = oidmd5;
    172 		olen = sizeof(oidmd5);
    173 	}else{
    174 		sysfatal("bad alg in mkasn1");
    175 		return -1;
    176 	}
    177 
    178 	p = asn1;
    179 	*p++ = 0x30;	/* sequence */
    180 	p++;
    181 
    182 	*p++ = 0x30;	/* another sequence */
    183 	p++;
    184 
    185 	*p++ = 0x06;	/* object id */
    186 	*p++ = olen;
    187 	memmove(p, obj, olen);
    188 	p += olen;
    189 
    190 	*p++ = 0x05;	/* null */
    191 	*p++ = 0;
    192 
    193 	asn1[3] = p - (asn1+4);	/* end of inner sequence */
    194 
    195 	*p++ = 0x04;	/* octet string */
    196 	*p++ = dlen;
    197 	memmove(p, d, dlen);
    198 	p += dlen;
    199 
    200 	asn1[1] = p - (asn1+2);	/* end of outer sequence */
    201 	return p-asn1;
    202 }