Back to index

lightning-sunbird  0.9+nobinonly
dersubr.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  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "secder.h"
00038 #include <limits.h>
00039 #include "secerr.h"
00040 
00041 int
00042 DER_LengthLength(uint32 len)
00043 {
00044     if (len > 127) {
00045        if (len > 255) {
00046            if (len > 65535L) {
00047               if (len > 16777215L) {
00048                   return 5;
00049               } else {
00050                   return 4;
00051               }
00052            } else {
00053               return 3;
00054            }
00055        } else {
00056            return 2;
00057        }
00058     } else {
00059        return 1;
00060     }
00061 }
00062 
00063 unsigned char *
00064 DER_StoreHeader(unsigned char *buf, unsigned int code, uint32 len)
00065 {
00066     unsigned char b[4];
00067 
00068     b[0] = (unsigned char)(len >> 24);
00069     b[1] = (unsigned char)(len >> 16);
00070     b[2] = (unsigned char)(len >> 8);
00071     b[3] = (unsigned char)len;
00072     if ((code & DER_TAGNUM_MASK) == DER_SET
00073        || (code & DER_TAGNUM_MASK) == DER_SEQUENCE)
00074        code |= DER_CONSTRUCTED;
00075     *buf++ = code;
00076     if (len > 127) {
00077        if (len > 255) {
00078            if (len > 65535) {
00079               if (len > 16777215) {
00080                   *buf++ = 0x84;
00081                   *buf++ = b[0];
00082                   *buf++ = b[1];
00083                   *buf++ = b[2];
00084                   *buf++ = b[3];
00085               } else {
00086                   *buf++ = 0x83;
00087                   *buf++ = b[1];
00088                   *buf++ = b[2];
00089                   *buf++ = b[3];
00090               }
00091            } else {
00092               *buf++ = 0x82;
00093               *buf++ = b[2];
00094               *buf++ = b[3];
00095            }
00096        } else {
00097            *buf++ = 0x81;
00098            *buf++ = b[3];
00099        }
00100     } else {
00101        *buf++ = b[3];
00102     }
00103     return buf;
00104 }
00105 
00106 /*
00107  * XXX This should be rewritten, generalized, to take a long instead
00108  * of an int32.
00109  */
00110 SECStatus
00111 DER_SetInteger(PRArenaPool *arena, SECItem *it, int32 i)
00112 {
00113     unsigned char bb[4];
00114     unsigned len;
00115 
00116     bb[0] = (unsigned char) (i >> 24);
00117     bb[1] = (unsigned char) (i >> 16);
00118     bb[2] = (unsigned char) (i >> 8);
00119     bb[3] = (unsigned char) (i);
00120 
00121     /*
00122     ** Small integers are encoded in a single byte. Larger integers
00123     ** require progressively more space.
00124     */
00125     if (i < -128) {
00126        if (i < -32768L) {
00127            if (i < -8388608L) {
00128               len = 4;
00129            } else {
00130               len = 3;
00131            }
00132        } else {
00133            len = 2;
00134        }
00135     } else if (i > 127) {
00136        if (i > 32767L) {
00137            if (i > 8388607L) {
00138               len = 4;
00139            } else {
00140               len = 3;
00141            }
00142        } else {
00143            len = 2;
00144        }
00145     } else {
00146        len = 1;
00147     }
00148     it->data = (unsigned char*) PORT_ArenaAlloc(arena, len);
00149     if (!it->data) {
00150        return SECFailure;
00151     }
00152     it->len = len;
00153     PORT_Memcpy(it->data, bb + (4 - len), len);
00154     return SECSuccess;
00155 }
00156 
00157 /*
00158  * XXX This should be rewritten, generalized, to take an unsigned long instead
00159  * of a uint32.
00160  */
00161 SECStatus
00162 DER_SetUInteger(PRArenaPool *arena, SECItem *it, uint32 ui)
00163 {
00164     unsigned char bb[5];
00165     int len;
00166 
00167     bb[0] = 0;
00168     bb[1] = (unsigned char) (ui >> 24);
00169     bb[2] = (unsigned char) (ui >> 16);
00170     bb[3] = (unsigned char) (ui >> 8);
00171     bb[4] = (unsigned char) (ui);
00172 
00173     /*
00174     ** Small integers are encoded in a single byte. Larger integers
00175     ** require progressively more space.
00176     */
00177     if (ui > 0x7f) {
00178        if (ui > 0x7fff) {
00179            if (ui > 0x7fffffL) {
00180               if (ui >= 0x80000000L) {
00181                   len = 5;
00182               } else {
00183                   len = 4;
00184               }
00185            } else {
00186               len = 3;
00187            }
00188        } else {
00189            len = 2;
00190        }
00191     } else {
00192        len = 1;
00193     }
00194 
00195     it->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
00196     if (it->data == NULL) {
00197        return SECFailure;
00198     }
00199 
00200     it->len = len;
00201     PORT_Memcpy(it->data, bb + (sizeof(bb) - len), len);
00202 
00203     return SECSuccess;
00204 }
00205 
00206 /*
00207 ** Convert a der encoded *signed* integer into a machine integral value.
00208 ** If an underflow/overflow occurs, sets error code and returns min/max.
00209 */
00210 long
00211 DER_GetInteger(SECItem *it)
00212 {
00213     long ival = 0;
00214     unsigned len = it->len;
00215     unsigned char *cp = it->data;
00216     unsigned long overflow = 0x1ffUL << (((sizeof(ival) - 1) * 8) - 1);
00217     unsigned long ofloinit;
00218 
00219     if (*cp & 0x80)
00220        ival = -1L;
00221     ofloinit = ival & overflow;
00222 
00223     while (len) {
00224        if ((ival & overflow) != ofloinit) {
00225            PORT_SetError(SEC_ERROR_BAD_DER);
00226            if (ival < 0) {
00227               return LONG_MIN;
00228            }
00229            return LONG_MAX;
00230        }
00231        ival = ival << 8;
00232        ival |= *cp++;
00233        --len;
00234     }
00235     return ival;
00236 }
00237 
00238 /*
00239 ** Convert a der encoded *unsigned* integer into a machine integral value.
00240 ** If an underflow/overflow occurs, sets error code and returns min/max.
00241 */
00242 unsigned long
00243 DER_GetUInteger(SECItem *it)
00244 {
00245     unsigned long ival = 0;
00246     unsigned len = it->len;
00247     unsigned char *cp = it->data;
00248     unsigned long overflow = 0xffUL << ((sizeof(ival) - 1) * 8);
00249 
00250     /* Cannot put a negative value into an unsigned container. */
00251     if (*cp & 0x80) {
00252        PORT_SetError(SEC_ERROR_BAD_DER);
00253        return 0;
00254     }
00255 
00256     while (len) {
00257        if (ival & overflow) {
00258            PORT_SetError(SEC_ERROR_BAD_DER);
00259            return ULONG_MAX;
00260        }
00261        ival = ival << 8;
00262        ival |= *cp++;
00263        --len;
00264     }
00265     return ival;
00266 }