dsautil.c (7843B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 #include "cryptohi.h" 5 #include "secasn1.h" 6 #include "secitem.h" 7 #include "prerr.h" 8 9 #ifndef DSA1_SUBPRIME_LEN 10 #define DSA1_SUBPRIME_LEN 20 /* bytes */ 11 #endif 12 13 typedef struct { 14 SECItem r; 15 SECItem s; 16 } DSA_ASN1Signature; 17 18 const SEC_ASN1Template DSA_SignatureTemplate[] = { 19 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(DSA_ASN1Signature) }, 20 { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature, r) }, 21 { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature, s) }, 22 { 0 } 23 }; 24 25 /* Input is variable length multi-byte integer, MSB first (big endian). 26 ** Most signficant bit of first byte is NOT treated as a sign bit. 27 ** May be one or more leading bytes of zeros. 28 ** Output is variable length multi-byte integer, MSB first (big endian). 29 ** Most significant bit of first byte will be zero (positive sign bit) 30 ** No more than one leading zero byte. 31 ** Caller supplies dest buffer, and assures that it is long enough, 32 ** e.g. at least one byte longer that src's buffer. 33 */ 34 void 35 DSAU_ConvertUnsignedToSigned(SECItem *dest, SECItem *src) 36 { 37 unsigned char *pSrc = src->data; 38 unsigned char *pDst = dest->data; 39 unsigned int cntSrc = src->len; 40 41 /* skip any leading zeros. */ 42 while (cntSrc && !(*pSrc)) { 43 pSrc++; 44 cntSrc--; 45 } 46 if (!cntSrc) { 47 *pDst = 0; 48 dest->len = 1; 49 return; 50 } 51 52 if (*pSrc & 0x80) 53 *pDst++ = 0; 54 55 PORT_Memcpy(pDst, pSrc, cntSrc); 56 dest->len = (pDst - dest->data) + cntSrc; 57 } 58 59 /* 60 ** src is a buffer holding a signed variable length integer. 61 ** dest is a buffer which will be filled with an unsigned integer, 62 ** MSB first (big endian) with leading zeros, so that the last byte 63 ** of src will be the LSB of the integer. The result will be exactly 64 ** the length specified by the caller in dest->len. 65 ** src can be shorter than dest. src can be longer than dst, but only 66 ** if the extra leading bytes are zeros. 67 */ 68 SECStatus 69 DSAU_ConvertSignedToFixedUnsigned(SECItem *dest, SECItem *src) 70 { 71 unsigned char *pSrc = src->data; 72 unsigned char *pDst = dest->data; 73 unsigned int cntSrc = src->len; 74 unsigned int cntDst = dest->len; 75 int zCount = cntDst - cntSrc; 76 77 if (zCount > 0) { 78 PORT_Memset(pDst, 0, zCount); 79 PORT_Memcpy(pDst + zCount, pSrc, cntSrc); 80 return SECSuccess; 81 } 82 if (zCount <= 0) { 83 /* Source is longer than destination. Check for leading zeros. */ 84 while (zCount++ < 0) { 85 if (*pSrc++ != 0) 86 goto loser; 87 } 88 } 89 PORT_Memcpy(pDst, pSrc, cntDst); 90 return SECSuccess; 91 92 loser: 93 PORT_SetError(PR_INVALID_ARGUMENT_ERROR); 94 return SECFailure; 95 } 96 97 /* src is a "raw" ECDSA or DSA signature, the first half contains r 98 * and the second half contains s. dest is the DER encoded signature. 99 */ 100 static SECStatus 101 common_EncodeDerSig(SECItem *dest, SECItem *src) 102 { 103 SECItem *item; 104 SECItem srcItem; 105 DSA_ASN1Signature sig; 106 unsigned char *signedR; 107 unsigned char *signedS; 108 unsigned int len; 109 110 /* Allocate memory with room for an extra byte that 111 * may be required if the top bit in the first byte 112 * is already set. 113 */ 114 len = src->len / 2; 115 signedR = (unsigned char *)PORT_Alloc(len + 1); 116 if (!signedR) 117 return SECFailure; 118 signedS = (unsigned char *)PORT_ZAlloc(len + 1); 119 if (!signedS) { 120 if (signedR) 121 PORT_Free(signedR); 122 return SECFailure; 123 } 124 125 PORT_Memset(&sig, 0, sizeof(sig)); 126 127 /* Must convert r and s from "unsigned" integers to "signed" integers. 128 ** If the high order bit of the first byte (MSB) is 1, then must 129 ** prepend with leading zero. 130 ** Must remove all but one leading zero byte from numbers. 131 */ 132 sig.r.type = siUnsignedInteger; 133 sig.r.data = signedR; 134 sig.r.len = sizeof signedR; 135 sig.s.type = siUnsignedInteger; 136 sig.s.data = signedS; 137 sig.s.len = sizeof signedR; 138 139 srcItem.data = src->data; 140 srcItem.len = len; 141 142 DSAU_ConvertUnsignedToSigned(&sig.r, &srcItem); 143 srcItem.data += len; 144 DSAU_ConvertUnsignedToSigned(&sig.s, &srcItem); 145 146 item = SEC_ASN1EncodeItem(NULL, dest, &sig, DSA_SignatureTemplate); 147 if (signedR) 148 PORT_Free(signedR); 149 if (signedS) 150 PORT_Free(signedS); 151 if (item == NULL) 152 return SECFailure; 153 154 /* XXX leak item? */ 155 return SECSuccess; 156 } 157 158 /* src is a DER-encoded ECDSA or DSA signature. 159 ** Returns a newly-allocated SECItem structure, pointing at a newly allocated 160 ** buffer containing the "raw" signature, which is len bytes of r, 161 ** followed by len bytes of s. For DSA, len is the length of q. 162 ** For ECDSA, len depends on the key size used to create the signature. 163 */ 164 static SECItem * 165 common_DecodeDerSig(const SECItem *item, unsigned int len) 166 { 167 SECItem *result = NULL; 168 PORTCheapArenaPool arena; 169 SECStatus status; 170 DSA_ASN1Signature sig; 171 SECItem dst; 172 173 PORT_Memset(&sig, 0, sizeof(sig)); 174 175 /* Make enough room for r + s. */ 176 PORT_InitCheapArena(&arena, PR_MAX(2 * MAX_ECKEY_LEN, DSA_MAX_SIGNATURE_LEN)); 177 178 result = PORT_ZNew(SECItem); 179 if (result == NULL) 180 goto loser; 181 182 result->len = 2 * len; 183 result->data = (unsigned char *)PORT_Alloc(2 * len); 184 if (result->data == NULL) 185 goto loser; 186 187 sig.r.type = siUnsignedInteger; 188 sig.s.type = siUnsignedInteger; 189 status = SEC_QuickDERDecodeItem(&arena.arena, &sig, DSA_SignatureTemplate, item); 190 if (status != SECSuccess) 191 goto loser; 192 193 /* Convert sig.r and sig.s from variable length signed integers to 194 ** fixed length unsigned integers. 195 */ 196 dst.data = result->data; 197 dst.len = len; 198 status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.r); 199 if (status != SECSuccess) 200 goto loser; 201 202 dst.data += len; 203 status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.s); 204 if (status != SECSuccess) 205 goto loser; 206 207 done: 208 PORT_DestroyCheapArena(&arena); 209 210 return result; 211 212 loser: 213 if (result != NULL) { 214 SECITEM_FreeItem(result, PR_TRUE); 215 result = NULL; 216 } 217 goto done; 218 } 219 220 /* src is a "raw" DSA1 signature, 20 bytes of r followed by 20 bytes of s. 221 ** dest is the signature DER encoded. ? 222 */ 223 SECStatus 224 DSAU_EncodeDerSig(SECItem *dest, SECItem *src) 225 { 226 PORT_Assert(src->len == 2 * DSA1_SUBPRIME_LEN); 227 if (src->len != 2 * DSA1_SUBPRIME_LEN) { 228 PORT_SetError(PR_INVALID_ARGUMENT_ERROR); 229 return SECFailure; 230 } 231 232 return common_EncodeDerSig(dest, src); 233 } 234 235 /* src is a "raw" DSA signature of length len (len/2 bytes of r followed 236 ** by len/2 bytes of s). dest is the signature DER encoded. 237 */ 238 SECStatus 239 DSAU_EncodeDerSigWithLen(SECItem *dest, SECItem *src, unsigned int len) 240 { 241 242 PORT_Assert((src->len == len) && (len % 2 == 0)); 243 if ((src->len != len) || (src->len % 2 != 0)) { 244 PORT_SetError(PR_INVALID_ARGUMENT_ERROR); 245 return SECFailure; 246 } 247 248 return common_EncodeDerSig(dest, src); 249 } 250 251 /* src is a DER-encoded DSA signature. 252 ** Returns a newly-allocated SECItem structure, pointing at a newly allocated 253 ** buffer containing the "raw" DSA1 signature, which is 20 bytes of r, 254 ** followed by 20 bytes of s. 255 */ 256 SECItem * 257 DSAU_DecodeDerSig(const SECItem *item) 258 { 259 return common_DecodeDerSig(item, DSA1_SUBPRIME_LEN); 260 } 261 262 /* src is a DER-encoded ECDSA signature. 263 ** Returns a newly-allocated SECItem structure, pointing at a newly allocated 264 ** buffer containing the "raw" ECDSA signature of length len containing 265 ** r followed by s (both padded to take up exactly len/2 bytes). 266 */ 267 SECItem * 268 DSAU_DecodeDerSigToLen(const SECItem *item, unsigned int len) 269 { 270 return common_DecodeDerSig(item, len / 2); 271 }