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 }