1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 7 /* 8 * src/lib/krb5/asn.1/asn1_encode.c 9 * 10 * Copyright 1994 by the Massachusetts Institute of Technology. 11 * All Rights Reserved. 12 * 13 * Export of this software from the United States of America may 14 * require a specific license from the United States Government. 15 * It is the responsibility of any person or organization contemplating 16 * export to obtain such a license before exporting. 17 * 18 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 19 * distribute this software and its documentation for any purpose and 20 * without fee is hereby granted, provided that the above copyright 21 * notice appear in all copies and that both that copyright notice and 22 * this permission notice appear in supporting documentation, and that 23 * the name of M.I.T. not be used in advertising or publicity pertaining 24 * to distribution of the software without specific, written prior 25 * permission. Furthermore if you modify this software you must label 26 * your software as modified software and not distribute it in such a 27 * fashion that it might be confused with the original M.I.T. software. 28 * M.I.T. makes no representations about the suitability of 29 * this software for any purpose. It is provided "as is" without express 30 * or implied warranty. 31 */ 32 33 /* ASN.1 primitive encoders */ 34 35 #include "asn1_encode.h" 36 #include "asn1_make.h" 37 38 static asn1_error_code asn1_encode_integer_internal(asn1buf *buf, long val, 39 unsigned int *retlen) 40 { 41 asn1_error_code retval; 42 unsigned int length = 0; 43 long valcopy; 44 int digit; 45 46 valcopy = val; 47 do { 48 digit = (int) (valcopy&0xFF); 49 retval = asn1buf_insert_octet(buf,(asn1_octet) digit); 50 if(retval) return retval; 51 length++; 52 valcopy = valcopy >> 8; 53 } while (valcopy != 0 && valcopy != ~0); 54 55 if((val > 0) && ((digit&0x80) == 0x80)) { /* make sure the high bit is */ 56 retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */ 57 if(retval) return retval; 58 length++; 59 }else if((val < 0) && ((digit&0x80) != 0x80)){ 60 retval = asn1buf_insert_octet(buf,0xFF); 61 if(retval) return retval; 62 length++; 63 } 64 65 66 *retlen = length; 67 return 0; 68 } 69 70 asn1_error_code asn1_encode_integer(asn1buf * buf, long val, 71 unsigned int *retlen) 72 { 73 asn1_error_code retval; 74 unsigned int length = 0; 75 unsigned int partlen; 76 retval = asn1_encode_integer_internal(buf, val, &partlen); 77 if (retval) return retval; 78 79 length = partlen; 80 retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen); 81 if(retval) return retval; 82 length += partlen; 83 84 *retlen = length; 85 return 0; 86 } 87 88 asn1_error_code 89 asn1_encode_enumerated(asn1buf * buf, const long val, 90 unsigned int *retlen) 91 { 92 asn1_error_code retval; 93 unsigned int length = 0; 94 unsigned int partlen; 95 retval = asn1_encode_integer_internal(buf, val, &partlen); 96 if (retval) return retval; 97 98 length = partlen; 99 retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_ENUMERATED,length, &partlen); 100 if(retval) return retval; 101 length += partlen; 102 103 *retlen = length; 104 return 0; 105 } 106 107 asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, unsigned long val, 108 unsigned int *retlen) 109 { 110 asn1_error_code retval; 111 unsigned int length = 0; 112 unsigned int partlen; 113 unsigned long valcopy; 114 int digit; 115 116 valcopy = val; 117 do { 118 digit = (int) (valcopy&0xFF); 119 retval = asn1buf_insert_octet(buf,(asn1_octet) digit); 120 if(retval) return retval; 121 length++; 122 valcopy = valcopy >> 8; 123 } while (valcopy != 0 && valcopy != ~0); 124 125 if(digit&0x80) { /* make sure the high bit is */ 126 retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */ 127 if(retval) return retval; 128 length++; 129 } 130 131 retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen); 132 if(retval) return retval; 133 length += partlen; 134 135 *retlen = length; 136 return 0; 137 } 138 139 asn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len, 140 const asn1_octet *val, 141 unsigned int *retlen) 142 { 143 asn1_error_code retval; 144 unsigned int length; 145 146 retval = asn1buf_insert_octetstring(buf, len, val); 147 if (retval) return retval; 148 retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_OBJECTIDENTIFIER, 149 len, &length); 150 if (retval) return retval; 151 152 *retlen = len + length; 153 return 0; 154 } 155 156 asn1_error_code asn1_encode_octetstring(asn1buf *buf, unsigned int len, 157 const asn1_octet *val, 158 unsigned int *retlen) 159 { 160 asn1_error_code retval; 161 unsigned int length; 162 163 retval = asn1buf_insert_octetstring(buf,len,val); 164 if(retval) return retval; 165 retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_OCTETSTRING,len,&length); 166 if(retval) return retval; 167 168 *retlen = len + length; 169 return 0; 170 } 171 172 asn1_error_code asn1_encode_charstring(asn1buf *buf, unsigned int len, 173 const char *val, unsigned int *retlen) 174 { 175 asn1_error_code retval; 176 unsigned int length; 177 178 retval = asn1buf_insert_charstring(buf,len,val); 179 if(retval) return retval; 180 retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_OCTETSTRING,len,&length); 181 if(retval) return retval; 182 183 *retlen = len + length; 184 return 0; 185 } 186 187 asn1_error_code asn1_encode_null(asn1buf *buf, int *retlen) 188 { 189 asn1_error_code retval; 190 191 retval = asn1buf_insert_octet(buf,0x00); 192 if(retval) return retval; 193 retval = asn1buf_insert_octet(buf,0x05); 194 if(retval) return retval; 195 196 *retlen = 2; 197 return 0; 198 } 199 200 asn1_error_code asn1_encode_printablestring(asn1buf *buf, unsigned int len, 201 const char *val, int *retlen) 202 { 203 asn1_error_code retval; 204 unsigned int length; 205 206 retval = asn1buf_insert_charstring(buf,len,val); 207 if(retval) return retval; 208 retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_PRINTABLESTRING,len, &length); 209 if(retval) return retval; 210 211 *retlen = len + length; 212 return 0; 213 } 214 215 asn1_error_code asn1_encode_ia5string(asn1buf *buf, unsigned int len, 216 const char *val, int *retlen) 217 { 218 asn1_error_code retval; 219 unsigned int length; 220 221 retval = asn1buf_insert_charstring(buf,len,val); 222 if(retval) return retval; 223 retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_IA5STRING,len, &length); 224 if(retval) return retval; 225 226 *retlen = len + length; 227 return 0; 228 } 229 230 asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val, 231 unsigned int *retlen) 232 { 233 asn1_error_code retval; 234 struct tm *gtime, gtimebuf; 235 char s[16], *sp; 236 unsigned int length, sum=0; 237 time_t gmt_time = val; 238 239 /* 240 * Time encoding: YYYYMMDDhhmmssZ 241 */ 242 if (gmt_time == 0) { 243 sp = "19700101000000Z"; 244 } else { 245 246 /* 247 * Sanity check this just to be paranoid, as gmtime can return NULL, 248 * and some bogus implementations might overrun on the sprintf. 249 */ 250 #ifdef HAVE_GMTIME_R 251 # ifdef GMTIME_R_RETURNS_INT 252 if (gmtime_r(&gmt_time, >imebuf) != 0) 253 return ASN1_BAD_GMTIME; 254 # else 255 if (gmtime_r(&gmt_time, >imebuf) == NULL) 256 return ASN1_BAD_GMTIME; 257 # endif 258 #else 259 gtime = gmtime(&gmt_time); 260 if (gtime == NULL) 261 return ASN1_BAD_GMTIME; 262 memcpy(>imebuf, gtime, sizeof(gtimebuf)); 263 #endif 264 gtime = >imebuf; 265 266 if (gtime->tm_year > 8099 || gtime->tm_mon > 11 || 267 gtime->tm_mday > 31 || gtime->tm_hour > 23 || 268 gtime->tm_min > 59 || gtime->tm_sec > 59) 269 return ASN1_BAD_GMTIME; 270 sprintf(s, "%04d%02d%02d%02d%02d%02dZ", 271 1900+gtime->tm_year, gtime->tm_mon+1, gtime->tm_mday, 272 gtime->tm_hour, gtime->tm_min, gtime->tm_sec); 273 sp = s; 274 } 275 276 retval = asn1buf_insert_charstring(buf,15,sp); 277 if(retval) return retval; 278 sum = 15; 279 280 retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_GENERALTIME,sum,&length); 281 if(retval) return retval; 282 sum += length; 283 284 *retlen = sum; 285 return 0; 286 } 287 288 asn1_error_code asn1_encode_generalstring(asn1buf *buf, unsigned int len, 289 const char *val, 290 unsigned int *retlen) 291 { 292 asn1_error_code retval; 293 unsigned int length; 294 295 retval = asn1buf_insert_charstring(buf,len,val); 296 if(retval) return retval; 297 retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_GENERALSTRING,len, 298 &length); 299 if(retval) return retval; 300 301 *retlen = len + length; 302 return 0; 303 } 304