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