security/nss/lib/cryptohi/dsautil.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial