Back to index

lightning-sunbird  0.9+nobinonly
dsautil.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 #include "cryptohi.h"
00038 #include "secasn1.h"
00039 #include "secitem.h"
00040 #include "prerr.h"
00041 
00042 #ifndef DSA_SUBPRIME_LEN
00043 #define DSA_SUBPRIME_LEN 20 /* bytes */
00044 #endif
00045 
00046 typedef struct {
00047     SECItem r;
00048     SECItem s;
00049 } DSA_ASN1Signature;
00050 
00051 const SEC_ASN1Template DSA_SignatureTemplate[] =
00052 {
00053     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(DSA_ASN1Signature) },
00054     { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature,r) },
00055     { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature,s) },
00056     { 0, }
00057 };
00058 
00059 /* Input is variable length multi-byte integer, MSB first (big endian).
00060 ** Most signficant bit of first byte is NOT treated as a sign bit. 
00061 ** May be one or more leading bytes of zeros. 
00062 ** Output is variable length multi-byte integer, MSB first (big endian).
00063 ** Most significant bit of first byte will be zero (positive sign bit)
00064 ** No more than one leading zero byte.
00065 ** Caller supplies dest buffer, and assures that it is long enough,
00066 ** e.g. at least one byte longer that src's buffer.
00067 */
00068 void
00069 DSAU_ConvertUnsignedToSigned(SECItem *dest, SECItem *src)
00070 {
00071     unsigned char *pSrc = src->data;
00072     unsigned char *pDst = dest->data;
00073     unsigned int   cntSrc = src->len;
00074 
00075     /* skip any leading zeros. */
00076     while (cntSrc && !(*pSrc)) { 
00077        pSrc++; 
00078        cntSrc--;
00079     }
00080     if (!cntSrc) {
00081        *pDst = 0; 
00082        dest->len = 1; 
00083        return; 
00084     }
00085 
00086     if (*pSrc & 0x80)
00087        *pDst++ = 0;
00088 
00089     PORT_Memcpy(pDst, pSrc, cntSrc);
00090     dest->len = (pDst - dest->data) + cntSrc;
00091 }
00092 
00093 /*
00094 ** src is a buffer holding a signed variable length integer.
00095 ** dest is a buffer which will be filled with an unsigned integer,
00096 ** MSB first (big endian) with leading zeros, so that the last byte
00097 ** of src will be the LSB of the integer.  The result will be exactly
00098 ** the length specified by the caller in dest->len.
00099 ** src can be shorter than dest.  src can be longer than dst, but only
00100 ** if the extra leading bytes are zeros.
00101 */
00102 SECStatus
00103 DSAU_ConvertSignedToFixedUnsigned(SECItem *dest, SECItem *src)
00104 {
00105     unsigned char *pSrc = src->data;
00106     unsigned char *pDst = dest->data;
00107     unsigned int   cntSrc = src->len;
00108     unsigned int   cntDst = dest->len;
00109     int            zCount = cntDst - cntSrc;
00110 
00111     if (zCount > 0) {
00112        PORT_Memset(pDst, 0, zCount);
00113        PORT_Memcpy(pDst + zCount, pSrc, cntSrc);
00114        return SECSuccess;
00115     }
00116     if (zCount <= 0) {
00117        /* Source is longer than destination.  Check for leading zeros. */
00118        while (zCount++ < 0) {
00119            if (*pSrc++ != 0)
00120               goto loser;
00121        }
00122     }
00123     PORT_Memcpy(pDst, pSrc, cntDst);
00124     return SECSuccess;
00125 
00126 loser:
00127     PORT_SetError( PR_INVALID_ARGUMENT_ERROR );
00128     return SECFailure;
00129 }
00130 
00131 /* src is a "raw" ECDSA or DSA signature, the first half contains r
00132  * and the second half contains s. dest is the DER encoded signature.
00133 */
00134 static SECStatus
00135 common_EncodeDerSig(SECItem *dest, SECItem *src)
00136 {
00137     SECItem *         item;
00138     SECItem           srcItem;
00139     DSA_ASN1Signature sig;
00140     unsigned char     *signedR;
00141     unsigned char     *signedS;
00142     unsigned int len;
00143 
00144     /* Allocate memory with room for an extra byte that
00145      * may be required if the top bit in the first byte
00146      * is already set.
00147      */
00148     len = src->len/2;
00149     signedR = (unsigned char *) PORT_Alloc(len + 1);
00150     if (!signedR) return SECFailure;
00151     signedS = (unsigned char *) PORT_ZAlloc(len + 1);
00152     if (!signedS) {
00153         if (signedR) PORT_Free(signedR);
00154        return SECFailure;
00155     }
00156 
00157     PORT_Memset(&sig, 0, sizeof(sig));
00158 
00159     /* Must convert r and s from "unsigned" integers to "signed" integers.
00160     ** If the high order bit of the first byte (MSB) is 1, then must
00161     ** prepend with leading zero.  
00162     ** Must remove all but one leading zero byte from numbers.
00163     */
00164     sig.r.type = siUnsignedInteger;
00165     sig.r.data = signedR;
00166     sig.r.len  = sizeof signedR;
00167     sig.s.type = siUnsignedInteger;
00168     sig.s.data = signedS;
00169     sig.s.len  = sizeof signedR;
00170 
00171     srcItem.data = src->data;
00172     srcItem.len  = len;
00173 
00174     DSAU_ConvertUnsignedToSigned(&sig.r, &srcItem);
00175     srcItem.data += len;
00176     DSAU_ConvertUnsignedToSigned(&sig.s, &srcItem);
00177 
00178     item = SEC_ASN1EncodeItem(NULL, dest, &sig, DSA_SignatureTemplate);
00179     if (signedR) PORT_Free(signedR);
00180     if (signedS) PORT_Free(signedS);
00181     if (item == NULL)
00182        return SECFailure;
00183 
00184     /* XXX leak item? */
00185     return SECSuccess;
00186 }
00187 
00188 /* src is a DER-encoded ECDSA or DSA signature.
00189 ** Returns a newly-allocated SECItem structure, pointing at a newly allocated
00190 ** buffer containing the "raw" signature, which is len bytes of r,
00191 ** followed by len bytes of s. For DSA, len is always DSA_SUBPRIME_LEN.
00192 ** For ECDSA, len depends on the key size used to create the signature.
00193 */
00194 static SECItem *
00195 common_DecodeDerSig(SECItem *item, unsigned int len)
00196 {
00197     SECItem *         result = NULL;
00198     SECStatus         status;
00199     DSA_ASN1Signature sig;
00200     SECItem           dst;
00201 
00202     PORT_Memset(&sig, 0, sizeof(sig));
00203 
00204     result = PORT_ZNew(SECItem);
00205     if (result == NULL)
00206        goto loser;
00207 
00208     result->len  = 2 * len;
00209     result->data = (unsigned char*)PORT_Alloc(2 * len);
00210     if (result->data == NULL)
00211        goto loser;
00212 
00213     sig.r.type = siUnsignedInteger;
00214     sig.s.type = siUnsignedInteger;
00215     status = SEC_ASN1DecodeItem(NULL, &sig, DSA_SignatureTemplate, item);
00216     if (status != SECSuccess)
00217        goto loser;
00218 
00219     /* Convert sig.r and sig.s from variable  length signed integers to 
00220     ** fixed length unsigned integers.
00221     */
00222     dst.data = result->data;
00223     dst.len  = len;
00224     status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.r);
00225     if (status != SECSuccess)
00226        goto loser;
00227 
00228     dst.data += len;
00229     status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.s);
00230     if (status != SECSuccess)
00231        goto loser;
00232 
00233 done:
00234     if (sig.r.data != NULL)
00235        PORT_Free(sig.r.data);
00236     if (sig.s.data != NULL)
00237        PORT_Free(sig.s.data);
00238 
00239     return result;
00240 
00241 loser:
00242     if (result != NULL) {
00243        SECITEM_FreeItem(result, PR_TRUE);
00244        result = NULL;
00245     }
00246     goto done;
00247 }
00248 
00249 /* src is a "raw" DSA signature, 20 bytes of r followed by 20 bytes of s.
00250 ** dest is the signature DER encoded. ?
00251 */
00252 SECStatus
00253 DSAU_EncodeDerSig(SECItem *dest, SECItem *src)
00254 {
00255     PORT_Assert(src->len == 2 * DSA_SUBPRIME_LEN);
00256     if (src->len != 2 * DSA_SUBPRIME_LEN) {
00257        PORT_SetError( PR_INVALID_ARGUMENT_ERROR );
00258        return SECFailure;
00259     }
00260 
00261     return common_EncodeDerSig(dest, src);
00262 }
00263 
00264 /* src is a "raw" DSA signature of length len (len/2 bytes of r followed
00265 ** by len/2 bytes of s). dest is the signature DER encoded.
00266 */
00267 SECStatus
00268 DSAU_EncodeDerSigWithLen(SECItem *dest, SECItem *src, unsigned int len)
00269 {
00270 
00271     PORT_Assert((src->len == len) && (len % 2 == 0));
00272     if ((src->len != len) || (src->len % 2 != 0)) {
00273        PORT_SetError( PR_INVALID_ARGUMENT_ERROR );
00274        return SECFailure;
00275     }
00276 
00277     return common_EncodeDerSig(dest, src);
00278 }
00279 
00280 /* src is a DER-encoded DSA signature.
00281 ** Returns a newly-allocated SECItem structure, pointing at a newly allocated
00282 ** buffer containing the "raw" DSA signature, which is 20 bytes of r,
00283 ** followed by 20 bytes of s.
00284 */
00285 SECItem *
00286 DSAU_DecodeDerSig(SECItem *item)
00287 {
00288     return common_DecodeDerSig(item, DSA_SUBPRIME_LEN);
00289 }
00290 
00291 /* src is a DER-encoded ECDSA signature.
00292 ** Returns a newly-allocated SECItem structure, pointing at a newly allocated
00293 ** buffer containing the "raw" ECDSA signature of length len containing
00294 ** r followed by s (both padded to take up exactly len/2 bytes).
00295 */
00296 SECItem *
00297 DSAU_DecodeDerSigToLen(SECItem *item, unsigned int len)
00298 {
00299     return common_DecodeDerSig(item, len/2);
00300 }