security/nss/lib/util/dersubr.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/util/dersubr.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,246 @@
     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 +
     1.8 +#include "secder.h"
     1.9 +#include <limits.h>
    1.10 +#include "secerr.h"
    1.11 +
    1.12 +int
    1.13 +DER_LengthLength(PRUint32 len)
    1.14 +{
    1.15 +    if (len > 127) {
    1.16 +	if (len > 255) {
    1.17 +	    if (len > 65535L) {
    1.18 +		if (len > 16777215L) {
    1.19 +		    return 5;
    1.20 +		} else {
    1.21 +		    return 4;
    1.22 +		}
    1.23 +	    } else {
    1.24 +		return 3;
    1.25 +	    }
    1.26 +	} else {
    1.27 +	    return 2;
    1.28 +	}
    1.29 +    } else {
    1.30 +	return 1;
    1.31 +    }
    1.32 +}
    1.33 +
    1.34 +unsigned char *
    1.35 +DER_StoreHeader(unsigned char *buf, unsigned int code, PRUint32 len)
    1.36 +{
    1.37 +    unsigned char b[4];
    1.38 +
    1.39 +    b[0] = (unsigned char)(len >> 24);
    1.40 +    b[1] = (unsigned char)(len >> 16);
    1.41 +    b[2] = (unsigned char)(len >> 8);
    1.42 +    b[3] = (unsigned char)len;
    1.43 +    if ((code & DER_TAGNUM_MASK) == DER_SET
    1.44 +	|| (code & DER_TAGNUM_MASK) == DER_SEQUENCE)
    1.45 +	code |= DER_CONSTRUCTED;
    1.46 +    *buf++ = code;
    1.47 +    if (len > 127) {
    1.48 +	if (len > 255) {
    1.49 +	    if (len > 65535) {
    1.50 +		if (len > 16777215) {
    1.51 +		    *buf++ = 0x84;
    1.52 +		    *buf++ = b[0];
    1.53 +		    *buf++ = b[1];
    1.54 +		    *buf++ = b[2];
    1.55 +		    *buf++ = b[3];
    1.56 +		} else {
    1.57 +		    *buf++ = 0x83;
    1.58 +		    *buf++ = b[1];
    1.59 +		    *buf++ = b[2];
    1.60 +		    *buf++ = b[3];
    1.61 +		}
    1.62 +	    } else {
    1.63 +		*buf++ = 0x82;
    1.64 +		*buf++ = b[2];
    1.65 +		*buf++ = b[3];
    1.66 +	    }
    1.67 +	} else {
    1.68 +	    *buf++ = 0x81;
    1.69 +	    *buf++ = b[3];
    1.70 +	}
    1.71 +    } else {
    1.72 +	*buf++ = b[3];
    1.73 +    }
    1.74 +    return buf;
    1.75 +}
    1.76 +
    1.77 +/*
    1.78 + * XXX This should be rewritten, generalized, to take a long instead
    1.79 + * of a PRInt32.
    1.80 + */
    1.81 +SECStatus
    1.82 +DER_SetInteger(PLArenaPool *arena, SECItem *it, PRInt32 i)
    1.83 +{
    1.84 +    unsigned char bb[4];
    1.85 +    unsigned len;
    1.86 +
    1.87 +    bb[0] = (unsigned char) (i >> 24);
    1.88 +    bb[1] = (unsigned char) (i >> 16);
    1.89 +    bb[2] = (unsigned char) (i >> 8);
    1.90 +    bb[3] = (unsigned char) (i);
    1.91 +
    1.92 +    /*
    1.93 +    ** Small integers are encoded in a single byte. Larger integers
    1.94 +    ** require progressively more space.
    1.95 +    */
    1.96 +    if (i < -128) {
    1.97 +	if (i < -32768L) {
    1.98 +	    if (i < -8388608L) {
    1.99 +		len = 4;
   1.100 +	    } else {
   1.101 +		len = 3;
   1.102 +	    }
   1.103 +	} else {
   1.104 +	    len = 2;
   1.105 +	}
   1.106 +    } else if (i > 127) {
   1.107 +	if (i > 32767L) {
   1.108 +	    if (i > 8388607L) {
   1.109 +		len = 4;
   1.110 +	    } else {
   1.111 +		len = 3;
   1.112 +	    }
   1.113 +	} else {
   1.114 +	    len = 2;
   1.115 +	}
   1.116 +    } else {
   1.117 +	len = 1;
   1.118 +    }
   1.119 +    it->data = (unsigned char*) PORT_ArenaAlloc(arena, len);
   1.120 +    if (!it->data) {
   1.121 +	return SECFailure;
   1.122 +    }
   1.123 +    it->len = len;
   1.124 +    PORT_Memcpy(it->data, bb + (4 - len), len);
   1.125 +    return SECSuccess;
   1.126 +}
   1.127 +
   1.128 +/*
   1.129 + * XXX This should be rewritten, generalized, to take an unsigned long instead
   1.130 + * of a PRUint32.
   1.131 + */
   1.132 +SECStatus
   1.133 +DER_SetUInteger(PLArenaPool *arena, SECItem *it, PRUint32 ui)
   1.134 +{
   1.135 +    unsigned char bb[5];
   1.136 +    int len;
   1.137 +
   1.138 +    bb[0] = 0;
   1.139 +    bb[1] = (unsigned char) (ui >> 24);
   1.140 +    bb[2] = (unsigned char) (ui >> 16);
   1.141 +    bb[3] = (unsigned char) (ui >> 8);
   1.142 +    bb[4] = (unsigned char) (ui);
   1.143 +
   1.144 +    /*
   1.145 +    ** Small integers are encoded in a single byte. Larger integers
   1.146 +    ** require progressively more space.
   1.147 +    */
   1.148 +    if (ui > 0x7f) {
   1.149 +	if (ui > 0x7fff) {
   1.150 +	    if (ui > 0x7fffffL) {
   1.151 +		if (ui >= 0x80000000L) {
   1.152 +		    len = 5;
   1.153 +		} else {
   1.154 +		    len = 4;
   1.155 +		}
   1.156 +	    } else {
   1.157 +		len = 3;
   1.158 +	    }
   1.159 +	} else {
   1.160 +	    len = 2;
   1.161 +	}
   1.162 +    } else {
   1.163 +	len = 1;
   1.164 +    }
   1.165 +
   1.166 +    it->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
   1.167 +    if (it->data == NULL) {
   1.168 +	return SECFailure;
   1.169 +    }
   1.170 +
   1.171 +    it->len = len;
   1.172 +    PORT_Memcpy(it->data, bb + (sizeof(bb) - len), len);
   1.173 +
   1.174 +    return SECSuccess;
   1.175 +}
   1.176 +
   1.177 +/*
   1.178 +** Convert a der encoded *signed* integer into a machine integral value.
   1.179 +** If an underflow/overflow occurs, sets error code and returns min/max.
   1.180 +*/
   1.181 +long
   1.182 +DER_GetInteger(const SECItem *it)
   1.183 +{
   1.184 +    long ival = 0;
   1.185 +    unsigned len = it->len;
   1.186 +    unsigned char *cp = it->data;
   1.187 +    unsigned long overflow = 0x1ffUL << (((sizeof(ival) - 1) * 8) - 1);
   1.188 +    unsigned long ofloinit;
   1.189 +
   1.190 +    PORT_Assert(len);
   1.191 +    if (!len) {
   1.192 +	PORT_SetError(SEC_ERROR_INPUT_LEN);
   1.193 +	return 0;
   1.194 +    }
   1.195 +
   1.196 +    if (*cp & 0x80)
   1.197 +    	ival = -1L;
   1.198 +    ofloinit = ival & overflow;
   1.199 +
   1.200 +    while (len) {
   1.201 +	if ((ival & overflow) != ofloinit) {
   1.202 +	    PORT_SetError(SEC_ERROR_BAD_DER);
   1.203 +	    if (ival < 0) {
   1.204 +		return LONG_MIN;
   1.205 +	    }
   1.206 +	    return LONG_MAX;
   1.207 +	}
   1.208 +	ival = ival << 8;
   1.209 +	ival |= *cp++;
   1.210 +	--len;
   1.211 +    }
   1.212 +    return ival;
   1.213 +}
   1.214 +
   1.215 +/*
   1.216 +** Convert a der encoded *unsigned* integer into a machine integral value.
   1.217 +** If an overflow occurs, sets error code and returns max.
   1.218 +*/
   1.219 +unsigned long
   1.220 +DER_GetUInteger(SECItem *it)
   1.221 +{
   1.222 +    unsigned long ival = 0;
   1.223 +    unsigned len = it->len;
   1.224 +    unsigned char *cp = it->data;
   1.225 +    unsigned long overflow = 0xffUL << ((sizeof(ival) - 1) * 8);
   1.226 +
   1.227 +    PORT_Assert(len);
   1.228 +    if (!len) {
   1.229 +	PORT_SetError(SEC_ERROR_INPUT_LEN);
   1.230 +	return 0;
   1.231 +    }
   1.232 +
   1.233 +    /* Cannot put a negative value into an unsigned container. */
   1.234 +    if (*cp & 0x80) {
   1.235 +	PORT_SetError(SEC_ERROR_BAD_DER);
   1.236 +	return 0;
   1.237 +    }
   1.238 +
   1.239 +    while (len) {
   1.240 +	if (ival & overflow) {
   1.241 +	    PORT_SetError(SEC_ERROR_BAD_DER);
   1.242 +	    return ULONG_MAX;
   1.243 +	}
   1.244 +	ival = ival << 8;
   1.245 +	ival |= *cp++;
   1.246 +	--len;
   1.247 +    }
   1.248 +    return ival;
   1.249 +}

mercurial