security/nss/lib/cryptohi/dsautil.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/cryptohi/dsautil.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,267 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +#include "cryptohi.h"
     1.8 +#include "secasn1.h"
     1.9 +#include "secitem.h"
    1.10 +#include "prerr.h"
    1.11 +
    1.12 +#ifndef DSA1_SUBPRIME_LEN
    1.13 +#define DSA1_SUBPRIME_LEN 20	/* bytes */
    1.14 +#endif
    1.15 +
    1.16 +typedef struct {
    1.17 +    SECItem r;
    1.18 +    SECItem s;
    1.19 +} DSA_ASN1Signature;
    1.20 +
    1.21 +const SEC_ASN1Template DSA_SignatureTemplate[] =
    1.22 +{
    1.23 +    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(DSA_ASN1Signature) },
    1.24 +    { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature,r) },
    1.25 +    { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature,s) },
    1.26 +    { 0, }
    1.27 +};
    1.28 +
    1.29 +/* Input is variable length multi-byte integer, MSB first (big endian).
    1.30 +** Most signficant bit of first byte is NOT treated as a sign bit. 
    1.31 +** May be one or more leading bytes of zeros. 
    1.32 +** Output is variable length multi-byte integer, MSB first (big endian).
    1.33 +** Most significant bit of first byte will be zero (positive sign bit)
    1.34 +** No more than one leading zero byte.
    1.35 +** Caller supplies dest buffer, and assures that it is long enough,
    1.36 +** e.g. at least one byte longer that src's buffer.
    1.37 +*/
    1.38 +void
    1.39 +DSAU_ConvertUnsignedToSigned(SECItem *dest, SECItem *src)
    1.40 +{
    1.41 +    unsigned char *pSrc = src->data;
    1.42 +    unsigned char *pDst = dest->data;
    1.43 +    unsigned int   cntSrc = src->len;
    1.44 +
    1.45 +    /* skip any leading zeros. */
    1.46 +    while (cntSrc && !(*pSrc)) { 
    1.47 +    	pSrc++; 
    1.48 +	cntSrc--;
    1.49 +    }
    1.50 +    if (!cntSrc) {
    1.51 +    	*pDst = 0; 
    1.52 +	dest->len = 1; 
    1.53 +	return; 
    1.54 +    }
    1.55 +
    1.56 +    if (*pSrc & 0x80)
    1.57 +    	*pDst++ = 0;
    1.58 +
    1.59 +    PORT_Memcpy(pDst, pSrc, cntSrc);
    1.60 +    dest->len = (pDst - dest->data) + cntSrc;
    1.61 +}
    1.62 +
    1.63 +/*
    1.64 +** src is a buffer holding a signed variable length integer.
    1.65 +** dest is a buffer which will be filled with an unsigned integer,
    1.66 +** MSB first (big endian) with leading zeros, so that the last byte
    1.67 +** of src will be the LSB of the integer.  The result will be exactly
    1.68 +** the length specified by the caller in dest->len.
    1.69 +** src can be shorter than dest.  src can be longer than dst, but only
    1.70 +** if the extra leading bytes are zeros.
    1.71 +*/
    1.72 +SECStatus
    1.73 +DSAU_ConvertSignedToFixedUnsigned(SECItem *dest, SECItem *src)
    1.74 +{
    1.75 +    unsigned char *pSrc = src->data;
    1.76 +    unsigned char *pDst = dest->data;
    1.77 +    unsigned int   cntSrc = src->len;
    1.78 +    unsigned int   cntDst = dest->len;
    1.79 +    int            zCount = cntDst - cntSrc;
    1.80 +
    1.81 +    if (zCount > 0) {
    1.82 +    	PORT_Memset(pDst, 0, zCount);
    1.83 +	PORT_Memcpy(pDst + zCount, pSrc, cntSrc);
    1.84 +	return SECSuccess;
    1.85 +    }
    1.86 +    if (zCount <= 0) {
    1.87 +	/* Source is longer than destination.  Check for leading zeros. */
    1.88 +	while (zCount++ < 0) {
    1.89 +	    if (*pSrc++ != 0)
    1.90 +		goto loser;
    1.91 +	}
    1.92 +    }
    1.93 +    PORT_Memcpy(pDst, pSrc, cntDst);
    1.94 +    return SECSuccess;
    1.95 +
    1.96 +loser:
    1.97 +    PORT_SetError( PR_INVALID_ARGUMENT_ERROR );
    1.98 +    return SECFailure;
    1.99 +}
   1.100 +
   1.101 +/* src is a "raw" ECDSA or DSA signature, the first half contains r
   1.102 + * and the second half contains s. dest is the DER encoded signature.
   1.103 +*/
   1.104 +static SECStatus
   1.105 +common_EncodeDerSig(SECItem *dest, SECItem *src)
   1.106 +{
   1.107 +    SECItem *         item;
   1.108 +    SECItem           srcItem;
   1.109 +    DSA_ASN1Signature sig;
   1.110 +    unsigned char     *signedR;
   1.111 +    unsigned char     *signedS;
   1.112 +    unsigned int len;
   1.113 +
   1.114 +    /* Allocate memory with room for an extra byte that
   1.115 +     * may be required if the top bit in the first byte
   1.116 +     * is already set.
   1.117 +     */
   1.118 +    len = src->len/2;
   1.119 +    signedR = (unsigned char *) PORT_Alloc(len + 1);
   1.120 +    if (!signedR) return SECFailure;
   1.121 +    signedS = (unsigned char *) PORT_ZAlloc(len + 1);
   1.122 +    if (!signedS) {
   1.123 +        if (signedR) PORT_Free(signedR);
   1.124 +	return SECFailure;
   1.125 +    }
   1.126 +
   1.127 +    PORT_Memset(&sig, 0, sizeof(sig));
   1.128 +
   1.129 +    /* Must convert r and s from "unsigned" integers to "signed" integers.
   1.130 +    ** If the high order bit of the first byte (MSB) is 1, then must
   1.131 +    ** prepend with leading zero.  
   1.132 +    ** Must remove all but one leading zero byte from numbers.
   1.133 +    */
   1.134 +    sig.r.type = siUnsignedInteger;
   1.135 +    sig.r.data = signedR;
   1.136 +    sig.r.len  = sizeof signedR;
   1.137 +    sig.s.type = siUnsignedInteger;
   1.138 +    sig.s.data = signedS;
   1.139 +    sig.s.len  = sizeof signedR;
   1.140 +
   1.141 +    srcItem.data = src->data;
   1.142 +    srcItem.len  = len;
   1.143 +
   1.144 +    DSAU_ConvertUnsignedToSigned(&sig.r, &srcItem);
   1.145 +    srcItem.data += len;
   1.146 +    DSAU_ConvertUnsignedToSigned(&sig.s, &srcItem);
   1.147 +
   1.148 +    item = SEC_ASN1EncodeItem(NULL, dest, &sig, DSA_SignatureTemplate);
   1.149 +    if (signedR) PORT_Free(signedR);
   1.150 +    if (signedS) PORT_Free(signedS);
   1.151 +    if (item == NULL)
   1.152 +	return SECFailure;
   1.153 +
   1.154 +    /* XXX leak item? */
   1.155 +    return SECSuccess;
   1.156 +}
   1.157 +
   1.158 +/* src is a DER-encoded ECDSA or DSA signature.
   1.159 +** Returns a newly-allocated SECItem structure, pointing at a newly allocated
   1.160 +** buffer containing the "raw" signature, which is len bytes of r,
   1.161 +** followed by len bytes of s. For DSA, len is the length of q.
   1.162 +** For ECDSA, len depends on the key size used to create the signature.
   1.163 +*/
   1.164 +static SECItem *
   1.165 +common_DecodeDerSig(const SECItem *item, unsigned int len)
   1.166 +{
   1.167 +    SECItem *         result = NULL;
   1.168 +    SECStatus         status;
   1.169 +    DSA_ASN1Signature sig;
   1.170 +    SECItem           dst;
   1.171 +
   1.172 +    PORT_Memset(&sig, 0, sizeof(sig));
   1.173 +
   1.174 +    result = PORT_ZNew(SECItem);
   1.175 +    if (result == NULL)
   1.176 +	goto loser;
   1.177 +
   1.178 +    result->len  = 2 * len;
   1.179 +    result->data = (unsigned char*)PORT_Alloc(2 * len);
   1.180 +    if (result->data == NULL)
   1.181 +	goto loser;
   1.182 +
   1.183 +    sig.r.type = siUnsignedInteger;
   1.184 +    sig.s.type = siUnsignedInteger;
   1.185 +    status = SEC_ASN1DecodeItem(NULL, &sig, DSA_SignatureTemplate, item);
   1.186 +    if (status != SECSuccess)
   1.187 +	goto loser;
   1.188 +
   1.189 +    /* Convert sig.r and sig.s from variable  length signed integers to 
   1.190 +    ** fixed length unsigned integers.
   1.191 +    */
   1.192 +    dst.data = result->data;
   1.193 +    dst.len  = len;
   1.194 +    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.r);
   1.195 +    if (status != SECSuccess)
   1.196 +    	goto loser;
   1.197 +
   1.198 +    dst.data += len;
   1.199 +    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.s);
   1.200 +    if (status != SECSuccess)
   1.201 +    	goto loser;
   1.202 +
   1.203 +done:
   1.204 +    if (sig.r.data != NULL)
   1.205 +	PORT_Free(sig.r.data);
   1.206 +    if (sig.s.data != NULL)
   1.207 +	PORT_Free(sig.s.data);
   1.208 +
   1.209 +    return result;
   1.210 +
   1.211 +loser:
   1.212 +    if (result != NULL) {
   1.213 +	SECITEM_FreeItem(result, PR_TRUE);
   1.214 +	result = NULL;
   1.215 +    }
   1.216 +    goto done;
   1.217 +}
   1.218 +
   1.219 +/* src is a "raw" DSA1 signature, 20 bytes of r followed by 20 bytes of s.
   1.220 +** dest is the signature DER encoded. ?
   1.221 +*/
   1.222 +SECStatus
   1.223 +DSAU_EncodeDerSig(SECItem *dest, SECItem *src)
   1.224 +{
   1.225 +    PORT_Assert(src->len == 2 * DSA1_SUBPRIME_LEN);
   1.226 +    if (src->len != 2 * DSA1_SUBPRIME_LEN) {
   1.227 +    	PORT_SetError( PR_INVALID_ARGUMENT_ERROR );
   1.228 +	return SECFailure;
   1.229 +    }
   1.230 +
   1.231 +    return common_EncodeDerSig(dest, src);
   1.232 +}
   1.233 +
   1.234 +/* src is a "raw" DSA signature of length len (len/2 bytes of r followed
   1.235 +** by len/2 bytes of s). dest is the signature DER encoded.
   1.236 +*/
   1.237 +SECStatus
   1.238 +DSAU_EncodeDerSigWithLen(SECItem *dest, SECItem *src, unsigned int len)
   1.239 +{
   1.240 +
   1.241 +    PORT_Assert((src->len == len) && (len % 2 == 0));
   1.242 +    if ((src->len != len) || (src->len % 2 != 0)) {
   1.243 +    	PORT_SetError( PR_INVALID_ARGUMENT_ERROR );
   1.244 +	return SECFailure;
   1.245 +    }
   1.246 +
   1.247 +    return common_EncodeDerSig(dest, src);
   1.248 +}
   1.249 +
   1.250 +/* src is a DER-encoded DSA signature.
   1.251 +** Returns a newly-allocated SECItem structure, pointing at a newly allocated
   1.252 +** buffer containing the "raw" DSA1 signature, which is 20 bytes of r,
   1.253 +** followed by 20 bytes of s.
   1.254 +*/
   1.255 +SECItem *
   1.256 +DSAU_DecodeDerSig(const SECItem *item)
   1.257 +{
   1.258 +    return common_DecodeDerSig(item, DSA1_SUBPRIME_LEN);
   1.259 +}
   1.260 +
   1.261 +/* src is a DER-encoded ECDSA signature.
   1.262 +** Returns a newly-allocated SECItem structure, pointing at a newly allocated
   1.263 +** buffer containing the "raw" ECDSA signature of length len containing
   1.264 +** r followed by s (both padded to take up exactly len/2 bytes).
   1.265 +*/
   1.266 +SECItem *
   1.267 +DSAU_DecodeDerSigToLen(const SECItem *item, unsigned int len)
   1.268 +{
   1.269 +    return common_DecodeDerSig(item, len/2);
   1.270 +}

mercurial