blob: 9d5fe4acdb957df6a470cc2b71df2b2f43e66ee7 [file] [log] [blame]
vlmfa67ddc2004-06-03 03:38:44 +00001/*-
2 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
vlm6534a8d2004-10-20 15:40:04 +00005#define _POSIX_PTHREAD_SEMANTICS /* for Sun */
6#define _REENTRANT /* for Sun */
vlm39ba4c42004-09-22 16:06:28 +00007#include <asn_internal.h>
vlmfa67ddc2004-06-03 03:38:44 +00008#include <GeneralizedTime.h>
9#include <time.h>
10#include <errno.h>
11#ifndef __NO_ASSERT_H__
12#include <assert.h>
13#endif /* __NO_ASSERT_H__ */
14
vlmc12c2102004-09-04 04:43:28 +000015#if defined(WIN32)
vlm6e73a042004-08-11 07:17:22 +000016#warning PLEASE STOP AND READ!
vlmbed6f812004-09-17 06:46:10 +000017#warning localtime_r is implemented via localtime(), which may be not thread-safe.
18#warning gmtime_r is implemented via gmtime(), which may be not thread-safe.
vlmc48f2132004-08-12 03:52:53 +000019#warning
20#warning You must fix the code by inserting appropriate locking
21#warning if you want to use asn_GT2time() or asn_UT2time().
vlm6e73a042004-08-11 07:17:22 +000022#warning PLEASE STOP AND READ!
vlmc48f2132004-08-12 03:52:53 +000023
vlm17909e92004-09-02 05:20:39 +000024static struct tm *localtime_r(const time_t *tloc, struct tm *result) {
vlmc48f2132004-08-12 03:52:53 +000025 struct tm *tm;
26 if((tm = localtime(tloc)))
27 return memcpy(result, tm, sizeof(struct tm));
28 return 0;
29}
30
vlm17909e92004-09-02 05:20:39 +000031static struct tm *gmtime_r(const time_t *tloc, struct tm *result) {
vlmc48f2132004-08-12 03:52:53 +000032 struct tm *tm;
33 if((tm = gmtime(tloc)))
34 return memcpy(result, tm, sizeof(struct tm));
35 return 0;
36}
37
vlmbed6f812004-09-17 06:46:10 +000038#define tzset() _tzset()
vlm6534a8d2004-10-20 15:40:04 +000039#define putenv() _putenv()
vlmbed6f812004-09-17 06:46:10 +000040#define _EMULATE_TIMEGM
41
42#endif /* WIN32 */
43
vlm6534a8d2004-10-20 15:40:04 +000044#if defined(sun)
45#define _EMULATE_TIMEGM
46#endif
47
vlmbed6f812004-09-17 06:46:10 +000048/*
49 * Where to look for offset from GMT, Phase I.
50 * Several platforms are known.
51 */
52#if defined(__FreeBSD__) \
53 || (defined(__GNUC__) && defined(__APPLE_CC__)) \
54 || (defined __GLIBC__ && __GLIBC__ >= 2)
55#undef HAVE_TM_GMTOFF
56#define HAVE_TM_GMTOFF
57#endif /* BSDs and newer glibc */
58
59/*
60 * Where to look for offset from GMT, Phase II.
61 */
62#ifdef HAVE_TM_GMTOFF
63#define GMTOFF(tm) ((tm).tm_gmtoff)
64#else /* HAVE_TM_GMTOFF */
65#define GMTOFF(tm) (-timezone)
66#endif /* HAVE_TM_GMTOFF */
67
68/*
69 * Override our GMTOFF decision for other known platforms.
70 */
71#ifdef __CYGWIN__
72#undef GMTOFF
73static long GMTOFF(struct tm a){
74 struct tm *lt;
75 time_t local_time, gmt_time;
76 long zone;
77
78 tzset();
79 gmt_time = time (NULL);
80
81 lt = gmtime(&gmt_time);
82
83 local_time = mktime(lt);
84 return (gmt_time - local_time);
85}
86#define _EMULATE_TIMEGM
87
88#endif /* __CYGWIN__ */
89
90#ifdef _EMULATE_TIMEGM
vlm348a37a2004-08-12 03:58:25 +000091static time_t timegm(struct tm *tm) {
92 time_t tloc;
93 char *tz;
vlmd3692282004-08-12 07:47:03 +000094 char *buf;
vlm348a37a2004-08-12 03:58:25 +000095
96 tz = getenv("TZ");
vlm6534a8d2004-10-20 15:40:04 +000097 putenv("TZ=UTC");
vlmbed6f812004-09-17 06:46:10 +000098 tzset();
vlm348a37a2004-08-12 03:58:25 +000099 tloc = mktime(tm);
vlmd3692282004-08-12 07:47:03 +0000100 if (tz) {
vlmbed6f812004-09-17 06:46:10 +0000101 int bufsize = strlen(tz) + 4;
102 buf = alloca(bufsize);
103 snprintf(buf, bufsize, "TZ=%s", tz);
vlmd3692282004-08-12 07:47:03 +0000104 } else {
105 buf = "TZ=";
106 }
vlm6534a8d2004-10-20 15:40:04 +0000107 putenv(buf);
vlmbed6f812004-09-17 06:46:10 +0000108 tzset();
vlm348a37a2004-08-12 03:58:25 +0000109 return tloc;
110}
vlmbed6f812004-09-17 06:46:10 +0000111#endif /* _EMULATE_TIMEGM */
vlm348a37a2004-08-12 03:58:25 +0000112
vlm6e73a042004-08-11 07:17:22 +0000113
vlmfa67ddc2004-06-03 03:38:44 +0000114#ifndef __NO_ASN_TABLE__
115
116/*
117 * GeneralizedTime basic type description.
118 */
vlmef6355b2004-09-29 13:26:15 +0000119static ber_tlv_tag_t asn_DEF_GeneralizedTime_tags[] = {
vlm6678cb12004-09-26 13:10:40 +0000120 (ASN_TAG_CLASS_UNIVERSAL | (24 << 2)), /* [UNIVERSAL 24] IMPLICIT ...*/
121 (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), /* [UNIVERSAL 26] IMPLICIT ...*/
122 (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */
vlmfa67ddc2004-06-03 03:38:44 +0000123};
vlmef6355b2004-09-29 13:26:15 +0000124asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = {
vlmfa67ddc2004-06-03 03:38:44 +0000125 "GeneralizedTime",
vlm39ba4c42004-09-22 16:06:28 +0000126 OCTET_STRING_free,
127 GeneralizedTime_print,
vlmfa67ddc2004-06-03 03:38:44 +0000128 GeneralizedTime_constraint, /* Check validity of time */
129 OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
vlm81057a82004-08-07 03:52:26 +0000130 GeneralizedTime_encode_der, /* Implemented in terms of OCTET STRING */
vlm39ba4c42004-09-22 16:06:28 +0000131 0, /* Not implemented yet */
132 GeneralizedTime_encode_xer,
vlmfa67ddc2004-06-03 03:38:44 +0000133 0, /* Use generic outmost tag fetcher */
vlmef6355b2004-09-29 13:26:15 +0000134 asn_DEF_GeneralizedTime_tags,
135 sizeof(asn_DEF_GeneralizedTime_tags)
136 / sizeof(asn_DEF_GeneralizedTime_tags[0]) - 2,
137 asn_DEF_GeneralizedTime_tags,
138 sizeof(asn_DEF_GeneralizedTime_tags)
139 / sizeof(asn_DEF_GeneralizedTime_tags[0]),
vlme413c122004-08-20 13:23:42 +0000140 0, 0, /* No members */
vlmb42843a2004-06-05 08:17:50 +0000141 0 /* No specifics */
vlmfa67ddc2004-06-03 03:38:44 +0000142};
143
144#endif /* __NO_ASN_TABLE__ */
145
146/*
147 * Check that the time looks like the time.
148 */
149int
vlmef6355b2004-09-29 13:26:15 +0000150GeneralizedTime_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
vlmfa67ddc2004-06-03 03:38:44 +0000151 asn_app_consume_bytes_f *app_errlog, void *app_key) {
vlmda674682004-08-11 09:07:36 +0000152 const GeneralizedTime_t *st = (const GeneralizedTime_t *)sptr;
vlmfa67ddc2004-06-03 03:38:44 +0000153 time_t tloc;
154
155 errno = EPERM; /* Just an unlikely error code */
vlm81057a82004-08-07 03:52:26 +0000156 tloc = asn_GT2time(st, 0, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000157 if(tloc == -1 && errno != EPERM) {
vlme3f0f282004-08-11 09:44:13 +0000158 _ASN_ERRLOG(app_errlog, app_key,
vlm758530a2004-08-22 13:47:59 +0000159 "%s: Invalid time format: %s (%s:%d)",
160 td->name, strerror(errno), __FILE__, __LINE__);
vlmfa67ddc2004-06-03 03:38:44 +0000161 return -1;
162 }
163
164 return 0;
165}
166
vlm39ba4c42004-09-22 16:06:28 +0000167asn_enc_rval_t
vlmef6355b2004-09-29 13:26:15 +0000168GeneralizedTime_encode_der(asn_TYPE_descriptor_t *td, void *ptr,
vlm81057a82004-08-07 03:52:26 +0000169 int tag_mode, ber_tlv_tag_t tag,
170 asn_app_consume_bytes_f *cb, void *app_key) {
vlmda674682004-08-11 09:07:36 +0000171 GeneralizedTime_t *st = (GeneralizedTime_t *)ptr;
vlm39ba4c42004-09-22 16:06:28 +0000172 asn_enc_rval_t erval;
vlm81057a82004-08-07 03:52:26 +0000173
174 /* If not canonical DER, re-encode into canonical DER. */
vlmef6355b2004-09-29 13:26:15 +0000175 if(st->size && st->buf[st->size-1] != 0x5a) {
vlm81057a82004-08-07 03:52:26 +0000176 struct tm tm;
177 time_t tloc;
178
179 errno = EPERM;
180 tloc = asn_GT2time(st, &tm, 1); /* Recognize time */
181 if(tloc == -1 && errno != EPERM) {
182 /* Failed to recognize time. Fail completely. */
183 erval.encoded = -1;
184 erval.failed_type = td;
185 erval.structure_ptr = ptr;
186 return erval;
187 }
188 st = asn_time2GT(0, &tm, 1); /* Save time canonically */
189 if(!st) {
190 /* Memory allocation failure. */
191 erval.encoded = -1;
192 erval.failed_type = td;
193 erval.structure_ptr = ptr;
194 return erval;
195 }
196 }
197
198 erval = OCTET_STRING_encode_der(td, st, tag_mode, tag, cb, app_key);
199
200 if(st != ptr) {
201 FREEMEM(st->buf);
202 FREEMEM(st);
203 }
204
205 return erval;
206}
207
vlm39ba4c42004-09-22 16:06:28 +0000208asn_enc_rval_t
vlmef6355b2004-09-29 13:26:15 +0000209GeneralizedTime_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
vlm39ba4c42004-09-22 16:06:28 +0000210 int ilevel, enum xer_encoder_flags_e flags,
211 asn_app_consume_bytes_f *cb, void *app_key) {
212 OCTET_STRING_t st;
213
214 if(flags & XER_F_CANONICAL) {
215 char buf[32];
216 struct tm tm;
217 ssize_t ret;
218
219 errno = EPERM;
220 if(asn_GT2time((GeneralizedTime_t *)sptr, &tm, 1) == -1
221 && errno != EPERM)
222 _ASN_ENCODE_FAILED;
223
224 ret = snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ",
225 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
226 tm.tm_hour, tm.tm_min, tm.tm_sec);
227 assert(ret > 0 && ret < (int)sizeof(buf));
228
229 st.buf = (uint8_t *)buf;
230 st.size = ret;
231 sptr = &st;
232 }
233
234 return OCTET_STRING_encode_xer_ascii(td, sptr, ilevel, flags,
235 cb, app_key);
236}
237
vlmfa67ddc2004-06-03 03:38:44 +0000238int
vlmef6355b2004-09-29 13:26:15 +0000239GeneralizedTime_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
vlmfa67ddc2004-06-03 03:38:44 +0000240 asn_app_consume_bytes_f *cb, void *app_key) {
vlmda674682004-08-11 09:07:36 +0000241 const GeneralizedTime_t *st = (const GeneralizedTime_t *)sptr;
vlmfa67ddc2004-06-03 03:38:44 +0000242
vlmb42843a2004-06-05 08:17:50 +0000243 (void)td; /* Unused argument */
244 (void)ilevel; /* Unused argument */
245
vlmfa67ddc2004-06-03 03:38:44 +0000246 if(st && st->buf) {
247 char buf[32];
248 struct tm tm;
249 int ret;
250
251 errno = EPERM;
vlm81057a82004-08-07 03:52:26 +0000252 if(asn_GT2time(st, &tm, 1) == -1 && errno != EPERM)
vlm6678cb12004-09-26 13:10:40 +0000253 return (cb("<bad-value>", 11, app_key) < 0) ? -1 : 0;
vlmfa67ddc2004-06-03 03:38:44 +0000254
255 ret = snprintf(buf, sizeof(buf),
vlm81057a82004-08-07 03:52:26 +0000256 "%04d-%02d-%02d %02d:%02d%02d (GMT)",
vlmfa67ddc2004-06-03 03:38:44 +0000257 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
258 tm.tm_hour, tm.tm_min, tm.tm_sec);
vlmb42843a2004-06-05 08:17:50 +0000259 assert(ret > 0 && ret < (int)sizeof(buf));
vlm6678cb12004-09-26 13:10:40 +0000260 return (cb(buf, ret, app_key) < 0) ? -1 : 0;
vlmfa67ddc2004-06-03 03:38:44 +0000261 } else {
vlm6678cb12004-09-26 13:10:40 +0000262 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
vlmfa67ddc2004-06-03 03:38:44 +0000263 }
264}
265
vlmfa67ddc2004-06-03 03:38:44 +0000266time_t
vlm81057a82004-08-07 03:52:26 +0000267asn_GT2time(const GeneralizedTime_t *st, struct tm *ret_tm, int as_gmt) {
vlmfa67ddc2004-06-03 03:38:44 +0000268 struct tm tm_s;
269 uint8_t *buf;
270 uint8_t *end;
vlm81057a82004-08-07 03:52:26 +0000271 int gmtoff_h = 0;
272 int gmtoff_m = 0;
273 int gmtoff = 0; /* h + m */
vlmfa67ddc2004-06-03 03:38:44 +0000274 int offset_specified = 0;
275 time_t tloc;
276
277 if(!st || !st->buf) {
278 errno = EINVAL;
279 return -1;
280 } else {
281 buf = st->buf;
282 end = buf + st->size;
283 }
284
285 if(st->size < 10) {
286 errno = EINVAL;
287 return -1;
288 }
289
290 /*
291 * Decode first 10 bytes: "AAAAMMJJhh"
292 */
293 memset(&tm_s, 0, sizeof(tm_s));
294#undef B2F
295#undef B2T
296#define B2F(var) do { \
297 unsigned ch = *buf; \
298 if(ch < 0x30 && ch > 0x39) { \
299 errno = EINVAL; \
300 return -1; \
301 } else { \
302 var = var * 10 + (ch - 0x30); \
303 buf++; \
304 } \
305 } while(0)
306#define B2T(var) B2F(tm_s.var)
307
308 B2T(tm_year); /* 1: A */
309 B2T(tm_year); /* 2: A */
310 B2T(tm_year); /* 3: A */
311 B2T(tm_year); /* 4: A */
312 B2T(tm_mon); /* 5: M */
313 B2T(tm_mon); /* 6: M */
314 B2T(tm_mday); /* 7: J */
315 B2T(tm_mday); /* 8: J */
316 B2T(tm_hour); /* 9: h */
317 B2T(tm_hour); /* 0: h */
318
319 if(buf == end) goto local_finish;
320
321 /*
322 * Parse [mm[ss[(.|,)ffff]]]
323 * ^^
324 */
325 switch(*buf) {
326 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
327 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
328 tm_s.tm_min = (*buf++) - 0x30;
329 if(buf == end) { errno = EINVAL; return -1; }
330 B2T(tm_min);
331 break;
332 case 0x2B: case 0x2D: /* +, - */
333 goto offset;
334 case 0x5A: /* Z */
335 goto utc_finish;
336 default:
337 errno = EINVAL;
338 return -1;
339 }
340
341 if(buf == end) goto local_finish;
342
343 /*
344 * Parse [mm[ss[(.|,)ffff]]]
345 * ^^
346 */
347 switch(*buf) {
348 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
349 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
350 tm_s.tm_sec = (*buf++) - 0x30;
351 if(buf == end) { errno = EINVAL; return -1; }
352 B2T(tm_sec);
353 break;
354 case 0x2B: case 0x2D: /* +, - */
355 goto offset;
356 case 0x5A: /* Z */
357 goto utc_finish;
358 default:
359 errno = EINVAL;
360 return -1;
361 }
362
363 if(buf == end) goto local_finish;
364
365 /*
366 * Parse [mm[ss[(.|,)ffff]]]
367 * ^ ^
368 */
369 switch(*buf) {
370 case 0x2C: case 0x2E: /* (.|,) */
371 /* Fractions of seconds are not supported
372 * by time_t or struct tm. Skip them */
373 for(buf++; buf < end; buf++) {
374 switch(*buf) {
375 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
376 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
377 continue;
378 default:
379 break;
380 }
381 break;
382 }
383 }
384
385 if(buf == end) goto local_finish;
386
387 switch(*buf) {
388 case 0x2B: case 0x2D: /* +, - */
389 goto offset;
390 case 0x5A: /* Z */
391 goto utc_finish;
392 default:
393 errno = EINVAL;
394 return -1;
395 }
396
397
398offset:
399
400 if(end - buf < 3) {
401 errno = EINVAL;
402 return -1;
403 }
404 buf++;
vlm81057a82004-08-07 03:52:26 +0000405 B2F(gmtoff_h);
406 B2F(gmtoff_h);
vlmfa67ddc2004-06-03 03:38:44 +0000407 if(buf[-3] == 0x2D) /* Negative */
vlm81057a82004-08-07 03:52:26 +0000408 gmtoff = -1;
vlmfa67ddc2004-06-03 03:38:44 +0000409 else
vlm81057a82004-08-07 03:52:26 +0000410 gmtoff = 1;
vlmfa67ddc2004-06-03 03:38:44 +0000411
412 if((end - buf) == 2) {
vlm81057a82004-08-07 03:52:26 +0000413 B2F(gmtoff_m);
414 B2F(gmtoff_m);
vlmfa67ddc2004-06-03 03:38:44 +0000415 } else if(end != buf) {
416 errno = EINVAL;
417 return -1;
418 }
419
vlm81057a82004-08-07 03:52:26 +0000420 gmtoff = gmtoff * (3600 * gmtoff_h + 60 * gmtoff_m);
vlmfa67ddc2004-06-03 03:38:44 +0000421
422 /* Fall through */
423utc_finish:
424
425 offset_specified = 1;
426
427 /* Fall through */
428local_finish:
429
430 /*
431 * Validation.
432 */
433 if((tm_s.tm_mon > 12 || tm_s.tm_mon < 1)
434 || (tm_s.tm_mday > 31 || tm_s.tm_mday < 1)
435 || (tm_s.tm_hour > 23)
436 || (tm_s.tm_sec > 60)
437 ) {
438 errno = EINVAL;
439 return -1;
440 }
441
442 /* Canonicalize */
443 tm_s.tm_mon -= 1; /* 0 - 11 */
444 tm_s.tm_year -= 1900;
445 tm_s.tm_isdst = -1;
446
vlm81057a82004-08-07 03:52:26 +0000447 tm_s.tm_sec -= gmtoff;
448
449 /*** AT THIS POINT tm_s is either GMT or local (unknown) ****/
450
vlmc48f2132004-08-12 03:52:53 +0000451 if(offset_specified) {
vlm81057a82004-08-07 03:52:26 +0000452 tloc = timegm(&tm_s);
vlmc48f2132004-08-12 03:52:53 +0000453 } else {
vlm81057a82004-08-07 03:52:26 +0000454 /*
vlmef6355b2004-09-29 13:26:15 +0000455 * Without an offset (or "Z"),
vlm81057a82004-08-07 03:52:26 +0000456 * we can only guess that it is a local zone.
457 * Interpret it in this fashion.
458 */
459 tloc = mktime(&tm_s);
460 }
vlmfa67ddc2004-06-03 03:38:44 +0000461 if(tloc == -1) {
462 errno = EINVAL;
463 return -1;
464 }
465
vlm81057a82004-08-07 03:52:26 +0000466 if(ret_tm) {
467 if(as_gmt) {
468 if(offset_specified) {
469 *ret_tm = tm_s;
470 } else {
471 if(gmtime_r(&tloc, ret_tm) == 0) {
472 errno = EINVAL;
473 return -1;
474 }
475 }
476 } else {
477 if(localtime_r(&tloc, ret_tm) == 0) {
478 errno = EINVAL;
479 return -1;
480 }
vlmfa67ddc2004-06-03 03:38:44 +0000481 }
482 }
483
vlmfa67ddc2004-06-03 03:38:44 +0000484 return tloc;
485}
486
vlm81057a82004-08-07 03:52:26 +0000487
488GeneralizedTime_t *
489asn_time2GT(GeneralizedTime_t *opt_gt, const struct tm *tm, int force_gmt) {
490 struct tm tm_s;
491 long gmtoff;
492 const unsigned int buf_size = 24; /* 4+2+2 +2+2+2 +4 + cushion */
493 char *buf;
494 char *p;
495 int size;
496
497 /* Check arguments */
498 if(!tm) {
499 errno = EINVAL;
500 return 0;
501 }
502
503 /* Pre-allocate a buffer of sufficient yet small length */
vlm6678cb12004-09-26 13:10:40 +0000504 buf = (char *)MALLOC(buf_size);
vlm81057a82004-08-07 03:52:26 +0000505 if(!buf) return 0;
506
507 gmtoff = GMTOFF(*tm);
508
509 if(force_gmt && gmtoff) {
510 tm_s = *tm;
511 tm_s.tm_sec -= gmtoff;
512 timegm(&tm_s); /* Fix the time */
vlm81057a82004-08-07 03:52:26 +0000513 tm = &tm_s;
vlm65efbd02004-08-11 07:35:08 +0000514#ifdef HAVE_TM_GMTOFF
515 assert(!GMTOFF(tm_s)); /* Will fix itself */
516#else
517 gmtoff = 0; /* Intervention required */
518#endif
vlm81057a82004-08-07 03:52:26 +0000519 }
520
521 size = snprintf(buf, buf_size, "%04d%02d%02d%02d%02d%02d",
522 tm->tm_year + 1900,
523 tm->tm_mon + 1,
524 tm->tm_mday,
525 tm->tm_hour,
526 tm->tm_min,
527 tm->tm_sec
528 );
529 assert(size == 14);
530
531 p = buf + size;
532 if(force_gmt) {
vlmef6355b2004-09-29 13:26:15 +0000533 *p++ = 0x5a; /* "Z" */
vlm81057a82004-08-07 03:52:26 +0000534 *p++ = 0;
535 size++;
536 } else {
537 int ret = snprintf(p, buf_size - size, "%+03ld%02ld",
538 gmtoff / 3600, gmtoff % 3600);
539 assert(ret >= 5 && ret <= 7);
540 size += ret;
541 }
542
543 if(opt_gt) {
544 if(opt_gt->buf)
545 FREEMEM(opt_gt->buf);
546 } else {
vlm6678cb12004-09-26 13:10:40 +0000547 opt_gt = (GeneralizedTime_t *)CALLOC(1, sizeof *opt_gt);
vlm81057a82004-08-07 03:52:26 +0000548 if(!opt_gt) { free(buf); return 0; }
549 }
550
vlm1ff928d2004-08-11 08:10:13 +0000551 opt_gt->buf = (unsigned char *)buf;
vlm81057a82004-08-07 03:52:26 +0000552 opt_gt->size = size;
553
554 return opt_gt;
555}
556
557