17c478bd9Sstevel@tonic-gate /*
2*5caf4451SPeter Shoults  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /* Coding Buffer Implementation */
77c478bd9Sstevel@tonic-gate 
87c478bd9Sstevel@tonic-gate /*
97c478bd9Sstevel@tonic-gate   Implementation
107c478bd9Sstevel@tonic-gate 
117c478bd9Sstevel@tonic-gate     Encoding mode
127c478bd9Sstevel@tonic-gate 
137c478bd9Sstevel@tonic-gate     The encoding buffer is filled from bottom (lowest address) to top
147c478bd9Sstevel@tonic-gate     (highest address).  This makes it easier to expand the buffer,
157c478bd9Sstevel@tonic-gate     since realloc preserves the existing portion of the buffer.
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate     Note: Since ASN.1 encoding must be done in reverse, this means
187c478bd9Sstevel@tonic-gate     that you can't simply memcpy out the buffer data, since it will be
197c478bd9Sstevel@tonic-gate     backwards.  You need to reverse-iterate through it, instead.
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate     ***This decision may have been a mistake.  In practice, the
227c478bd9Sstevel@tonic-gate     implementation will probably be tuned such that reallocation is
237c478bd9Sstevel@tonic-gate     rarely necessary.  Also, the realloc probably has recopy the
247c478bd9Sstevel@tonic-gate     buffer itself, so we don't really gain that much by avoiding an
257c478bd9Sstevel@tonic-gate     explicit copy of the buffer.  --Keep this in mind for future reference.
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate     Decoding mode
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate     The decoding buffer is in normal order and is created by wrapping
317c478bd9Sstevel@tonic-gate     an asn1buf around a krb5_data structure.
327c478bd9Sstevel@tonic-gate   */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /* Abstraction Function
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate    Programs should use just pointers to asn1buf's (e.g. asn1buf *mybuf).
377c478bd9Sstevel@tonic-gate    These pointers must always point to a valid, allocated asn1buf
387c478bd9Sstevel@tonic-gate    structure or be NULL.
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate    The contents of the asn1buf represent an octet string.  This string
417c478bd9Sstevel@tonic-gate    begins at base and continues to the octet immediately preceding next.
427c478bd9Sstevel@tonic-gate    If next == base or mybuf == NULL, then the asn1buf represents an empty
437c478bd9Sstevel@tonic-gate    octet string. */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /* Representation Invariant
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate    Pointers to asn1buf's must always point to a valid, allocated
487c478bd9Sstevel@tonic-gate    asn1buf structure or be NULL.
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate    base points to a valid, allocated octet array or is NULL
517c478bd9Sstevel@tonic-gate    bound, if non-NULL, points to the last valid octet
527c478bd9Sstevel@tonic-gate    next >= base
53505d05c7Sgtb    next <= bound+2  (i.e. next should be able to step just past the bound,
547c478bd9Sstevel@tonic-gate                      but no further.  (The bound should move out in response
557c478bd9Sstevel@tonic-gate 		     to being crossed by next.)) */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #define ASN1BUF_OMIT_INLINE_FUNCS
587c478bd9Sstevel@tonic-gate #include "asn1buf.h"
597c478bd9Sstevel@tonic-gate #undef ASN1BUF_OMIT_INLINE_FUNCS
607c478bd9Sstevel@tonic-gate #include <stdio.h>
617c478bd9Sstevel@tonic-gate #include "asn1_get.h"
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #define asn1_is_eoc(class, num, indef)	\
647c478bd9Sstevel@tonic-gate ((class) == UNIVERSAL && !(num) && !(indef))
657c478bd9Sstevel@tonic-gate 
asn1buf_create(asn1buf ** buf)667c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_create(asn1buf **buf)
677c478bd9Sstevel@tonic-gate {
687c478bd9Sstevel@tonic-gate   *buf = (asn1buf*)malloc(sizeof(asn1buf));
697c478bd9Sstevel@tonic-gate   if (*buf == NULL) return ENOMEM;
707c478bd9Sstevel@tonic-gate   (*buf)->base = NULL;
717c478bd9Sstevel@tonic-gate   (*buf)->bound = NULL;
727c478bd9Sstevel@tonic-gate   (*buf)->next = NULL;
737c478bd9Sstevel@tonic-gate   return 0;
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate 
asn1buf_wrap_data(asn1buf * buf,const krb5_data * code)767c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_wrap_data(asn1buf *buf, const krb5_data *code)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate   if(code == NULL || code->data == NULL) return ASN1_MISSING_FIELD;
797c478bd9Sstevel@tonic-gate   buf->next = buf->base = code->data;
807c478bd9Sstevel@tonic-gate   buf->bound = code->data + code->length - 1;
817c478bd9Sstevel@tonic-gate   return 0;
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate 
asn1buf_imbed(asn1buf * subbuf,const asn1buf * buf,const unsigned int length,const int indef)847c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_imbed(asn1buf *subbuf, const asn1buf *buf, const unsigned int length, const int indef)
857c478bd9Sstevel@tonic-gate {
86*5caf4451SPeter Shoults   if (buf->next > buf->bound + 1) return ASN1_OVERRUN;
877c478bd9Sstevel@tonic-gate   subbuf->base = subbuf->next = buf->next;
887c478bd9Sstevel@tonic-gate   if (!indef) {
89*5caf4451SPeter Shoults       if (length > (size_t)(buf->bound + 1 - buf->next)) return ASN1_OVERRUN;
907c478bd9Sstevel@tonic-gate       subbuf->bound = subbuf->base + length - 1;
917c478bd9Sstevel@tonic-gate   } else /* constructed indefinite */
927c478bd9Sstevel@tonic-gate       subbuf->bound = buf->bound;
937c478bd9Sstevel@tonic-gate   return 0;
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate 
asn1buf_sync(asn1buf * buf,asn1buf * subbuf,asn1_class asn1class,asn1_tagnum lasttag,unsigned int length,int indef,int seqindef)967c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_sync(asn1buf *buf, asn1buf *subbuf,
977c478bd9Sstevel@tonic-gate 			     asn1_class asn1class, asn1_tagnum lasttag,
987c478bd9Sstevel@tonic-gate 			     unsigned int length, int indef, int seqindef)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate   asn1_error_code retval;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate   if (!seqindef) {
1037c478bd9Sstevel@tonic-gate     /* sequence was encoded as definite length */
1047c478bd9Sstevel@tonic-gate     buf->next = subbuf->bound + 1;
1057c478bd9Sstevel@tonic-gate   } else if (!asn1_is_eoc(asn1class, lasttag, indef)) {
1067c478bd9Sstevel@tonic-gate       retval = asn1buf_skiptail(subbuf, length, indef);
1077c478bd9Sstevel@tonic-gate       if (retval)
1087c478bd9Sstevel@tonic-gate 	  return retval;
1097c478bd9Sstevel@tonic-gate   } else {
1107c478bd9Sstevel@tonic-gate     /* We have just read the EOC octets. */
1117c478bd9Sstevel@tonic-gate     buf->next = subbuf->next;
1127c478bd9Sstevel@tonic-gate   }
1137c478bd9Sstevel@tonic-gate   return 0;
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
asn1buf_skiptail(asn1buf * buf,const unsigned int length,const int indef)1167c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_skiptail(asn1buf *buf, const unsigned int length, const int indef)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate   asn1_error_code retval;
1197c478bd9Sstevel@tonic-gate   taginfo t;
1207c478bd9Sstevel@tonic-gate   int nestlevel;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate   nestlevel = 1 + indef;
1237c478bd9Sstevel@tonic-gate   if (!indef) {
1247c478bd9Sstevel@tonic-gate     if (length <= buf->bound - buf->next + 1)
1257c478bd9Sstevel@tonic-gate       buf->next += length;
1267c478bd9Sstevel@tonic-gate     else
1277c478bd9Sstevel@tonic-gate       return ASN1_OVERRUN;
1287c478bd9Sstevel@tonic-gate   }
1297c478bd9Sstevel@tonic-gate   while (nestlevel > 0) {
130505d05c7Sgtb     if (buf->bound - buf->next + 1 <= 0)
131505d05c7Sgtb       return ASN1_OVERRUN;
1327c478bd9Sstevel@tonic-gate     retval = asn1_get_tag_2(buf, &t);
1337c478bd9Sstevel@tonic-gate     if (retval) return retval;
1347c478bd9Sstevel@tonic-gate     if (!t.indef) {
1357c478bd9Sstevel@tonic-gate       if (t.length <= buf->bound - buf->next + 1)
1367c478bd9Sstevel@tonic-gate 	buf->next += t.length;
1377c478bd9Sstevel@tonic-gate       else
1387c478bd9Sstevel@tonic-gate 	return ASN1_OVERRUN;
1397c478bd9Sstevel@tonic-gate     }
1407c478bd9Sstevel@tonic-gate     if (t.indef)
1417c478bd9Sstevel@tonic-gate       nestlevel++;
1427c478bd9Sstevel@tonic-gate     if (asn1_is_eoc(t.asn1class, t.tagnum, t.indef))
1437c478bd9Sstevel@tonic-gate       nestlevel--;		/* got an EOC encoding */
1447c478bd9Sstevel@tonic-gate   }
1457c478bd9Sstevel@tonic-gate   return 0;
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
asn1buf_destroy(asn1buf ** buf)1487c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_destroy(asn1buf **buf)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate   if (*buf != NULL) {
1517c478bd9Sstevel@tonic-gate     if ((*buf)->base != NULL) free((*buf)->base);
1527c478bd9Sstevel@tonic-gate     free(*buf);
1537c478bd9Sstevel@tonic-gate     *buf = NULL;
1547c478bd9Sstevel@tonic-gate   }
1557c478bd9Sstevel@tonic-gate   return 0;
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate #ifdef asn1buf_insert_octet
1597c478bd9Sstevel@tonic-gate #undef asn1buf_insert_octet
1607c478bd9Sstevel@tonic-gate #endif
asn1buf_insert_octet(asn1buf * buf,const int o)1617c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_insert_octet(asn1buf *buf, const int o)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate   asn1_error_code retval;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate   retval = asn1buf_ensure_space(buf,1U);
1667c478bd9Sstevel@tonic-gate   if(retval) return retval;
1677c478bd9Sstevel@tonic-gate   *(buf->next) = (char)o;
1687c478bd9Sstevel@tonic-gate   (buf->next)++;
1697c478bd9Sstevel@tonic-gate   return 0;
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
asn1buf_insert_octetstring(asn1buf * buf,const unsigned int len,const krb5_octet * s)1727c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_insert_octetstring(asn1buf *buf, const unsigned int len, const krb5_octet *s)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate   asn1_error_code retval;
1757c478bd9Sstevel@tonic-gate   int length;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate   retval = asn1buf_ensure_space(buf,len);
1787c478bd9Sstevel@tonic-gate   if(retval) return retval;
1797c478bd9Sstevel@tonic-gate   for(length=1; length<=len; length++,(buf->next)++)
1807c478bd9Sstevel@tonic-gate     *(buf->next) = (char)(s[len-length]);
1817c478bd9Sstevel@tonic-gate   return 0;
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
asn1buf_insert_charstring(asn1buf * buf,const unsigned int len,const char * s)1847c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_insert_charstring(asn1buf *buf, const unsigned int len, const char *s)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate   asn1_error_code retval;
1877c478bd9Sstevel@tonic-gate   int length;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate   retval = asn1buf_ensure_space(buf,len);
1907c478bd9Sstevel@tonic-gate   if(retval) return retval;
1917c478bd9Sstevel@tonic-gate   for(length=1; length<=len; length++,(buf->next)++)
1927c478bd9Sstevel@tonic-gate     *(buf->next) = (char)(s[len-length]);
1937c478bd9Sstevel@tonic-gate   return 0;
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate #undef asn1buf_remove_octet
asn1buf_remove_octet(asn1buf * buf,asn1_octet * o)1977c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_remove_octet(asn1buf *buf, asn1_octet *o)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate   if(buf->next > buf->bound) return ASN1_OVERRUN;
2007c478bd9Sstevel@tonic-gate   *o = (asn1_octet)(*((buf->next)++));
2017c478bd9Sstevel@tonic-gate   return 0;
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
asn1buf_remove_octetstring(asn1buf * buf,const unsigned int len,asn1_octet ** s)2047c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_remove_octetstring(asn1buf *buf, const unsigned int len, asn1_octet **s)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate   int i;
2077c478bd9Sstevel@tonic-gate 
208*5caf4451SPeter Shoults   if (buf->next > buf->bound + 1) return ASN1_OVERRUN;
2097c478bd9Sstevel@tonic-gate   if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN;
2107c478bd9Sstevel@tonic-gate   if (len == 0) {
2117c478bd9Sstevel@tonic-gate       *s = 0;
2127c478bd9Sstevel@tonic-gate       return 0;
2137c478bd9Sstevel@tonic-gate   }
2147c478bd9Sstevel@tonic-gate   *s = (asn1_octet*)malloc(len*sizeof(asn1_octet));
2157c478bd9Sstevel@tonic-gate   if (*s == NULL)
2167c478bd9Sstevel@tonic-gate       return ENOMEM;
2177c478bd9Sstevel@tonic-gate   for(i=0; i<len; i++)
2187c478bd9Sstevel@tonic-gate     (*s)[i] = (asn1_octet)(buf->next)[i];
2197c478bd9Sstevel@tonic-gate   buf->next += len;
2207c478bd9Sstevel@tonic-gate   return 0;
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
asn1buf_remove_charstring(asn1buf * buf,const unsigned int len,char ** s)2237c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_remove_charstring(asn1buf *buf, const unsigned int len, char **s)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate   int i;
2267c478bd9Sstevel@tonic-gate 
227*5caf4451SPeter Shoults   if (buf->next > buf->bound + 1) return ASN1_OVERRUN;
2287c478bd9Sstevel@tonic-gate   if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN;
2297c478bd9Sstevel@tonic-gate   if (len == 0) {
2307c478bd9Sstevel@tonic-gate       *s = 0;
2317c478bd9Sstevel@tonic-gate       return 0;
2327c478bd9Sstevel@tonic-gate   }
2337c478bd9Sstevel@tonic-gate   *s = (char*)malloc(len*sizeof(char));
2347c478bd9Sstevel@tonic-gate   if (*s == NULL) return ENOMEM;
2357c478bd9Sstevel@tonic-gate   for(i=0; i<len; i++)
2367c478bd9Sstevel@tonic-gate     (*s)[i] = (char)(buf->next)[i];
2377c478bd9Sstevel@tonic-gate   buf->next += len;
2387c478bd9Sstevel@tonic-gate   return 0;
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate 
asn1buf_remains(asn1buf * buf,int indef)2417c478bd9Sstevel@tonic-gate int asn1buf_remains(asn1buf *buf, int indef)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate   int remain;
2447c478bd9Sstevel@tonic-gate   if(buf == NULL || buf->base == NULL) return 0;
2457c478bd9Sstevel@tonic-gate   remain = buf->bound - buf->next +1;
2467c478bd9Sstevel@tonic-gate   if (remain <= 0) return remain;
2477c478bd9Sstevel@tonic-gate   /*
2487c478bd9Sstevel@tonic-gate    * Two 0 octets means the end of an indefinite encoding.
2497c478bd9Sstevel@tonic-gate    */
2507c478bd9Sstevel@tonic-gate   if (indef && remain >= 2 && !*(buf->next) && !*(buf->next + 1))
2517c478bd9Sstevel@tonic-gate       return 0;
2527c478bd9Sstevel@tonic-gate   else return remain;
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate 
asn12krb5_buf(const asn1buf * buf,krb5_data ** code)2557c478bd9Sstevel@tonic-gate asn1_error_code asn12krb5_buf(const asn1buf *buf, krb5_data **code)
2567c478bd9Sstevel@tonic-gate {
2577c478bd9Sstevel@tonic-gate   int i;
2587c478bd9Sstevel@tonic-gate   *code = (krb5_data*)calloc(1,sizeof(krb5_data));
2597c478bd9Sstevel@tonic-gate   if(*code == NULL) return ENOMEM;
2607c478bd9Sstevel@tonic-gate   (*code)->magic = KV5M_DATA;
2617c478bd9Sstevel@tonic-gate   (*code)->data = NULL;
2627c478bd9Sstevel@tonic-gate   (*code)->length = 0;
2637c478bd9Sstevel@tonic-gate   (*code)->length = asn1buf_len(buf);
2647c478bd9Sstevel@tonic-gate   (*code)->data = (char*)malloc((((*code)->length)+1)*sizeof(char));
2657c478bd9Sstevel@tonic-gate   if ((*code)->data == NULL) {
2667c478bd9Sstevel@tonic-gate     free(*code);
2677c478bd9Sstevel@tonic-gate     *code = NULL;
2687c478bd9Sstevel@tonic-gate     return ENOMEM;
2697c478bd9Sstevel@tonic-gate   }
2707c478bd9Sstevel@tonic-gate   for(i=0; i < (*code)->length; i++)
2717c478bd9Sstevel@tonic-gate     ((*code)->data)[i] = (buf->base)[((*code)->length)-i-1];
2727c478bd9Sstevel@tonic-gate   ((*code)->data)[(*code)->length] = '\0';
2737c478bd9Sstevel@tonic-gate   return 0;
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate /* These parse and unparse procedures should be moved out. They're
2797c478bd9Sstevel@tonic-gate    useful only for debugging and superfluous in the production version. */
2807c478bd9Sstevel@tonic-gate 
asn1buf_unparse(const asn1buf * buf,char ** s)2817c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_unparse(const asn1buf *buf, char **s)
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate   if(*s != NULL) free(*s);
2847c478bd9Sstevel@tonic-gate   if(buf == NULL){
2857c478bd9Sstevel@tonic-gate     *s = malloc(sizeof("<NULL>"));
2867c478bd9Sstevel@tonic-gate     if(*s == NULL) return ENOMEM;
2877c478bd9Sstevel@tonic-gate     strcpy(*s,"<NULL>");
2887c478bd9Sstevel@tonic-gate   }else if(buf->base == NULL){
2897c478bd9Sstevel@tonic-gate     *s = malloc(sizeof("<EMPTY>"));
2907c478bd9Sstevel@tonic-gate     if(*s == NULL) return ENOMEM;
2917c478bd9Sstevel@tonic-gate     strcpy(*s,"<EMPTY>");
2927c478bd9Sstevel@tonic-gate   }else{
2937c478bd9Sstevel@tonic-gate     unsigned int length = asn1buf_len(buf);
2947c478bd9Sstevel@tonic-gate     int i;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate     *s = calloc(length+1, sizeof(char));
2977c478bd9Sstevel@tonic-gate     if(*s == NULL) return ENOMEM;
2987c478bd9Sstevel@tonic-gate     (*s)[length] = '\0';
2997c478bd9Sstevel@tonic-gate     for(i=0; i<length; i++) ;
3007c478bd9Sstevel@tonic-gate /*      OLDDECLARG( (*s)[i] = , (buf->base)[length-i-1]) */
3017c478bd9Sstevel@tonic-gate   }
3027c478bd9Sstevel@tonic-gate   return 0;
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
asn1buf_hex_unparse(const asn1buf * buf,char ** s)3057c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_hex_unparse(const asn1buf *buf, char **s)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate #define hexchar(d) ((d)<=9 ? ('0'+(d)) :\
3087c478bd9Sstevel@tonic-gate 		    ((d)<=15 ? ('A'+(d)-10) :\
3097c478bd9Sstevel@tonic-gate 		    'X'))
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate   if(*s != NULL) free(*s);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate   if(buf == NULL){
3147c478bd9Sstevel@tonic-gate     *s = malloc(sizeof("<NULL>"));
3157c478bd9Sstevel@tonic-gate     if(*s == NULL) return ENOMEM;
3167c478bd9Sstevel@tonic-gate     strcpy(*s,"<NULL>");
3177c478bd9Sstevel@tonic-gate   }else if(buf->base == NULL){
3187c478bd9Sstevel@tonic-gate     *s = malloc(sizeof("<EMPTY>"));
3197c478bd9Sstevel@tonic-gate     if(*s == NULL) return ENOMEM;
3207c478bd9Sstevel@tonic-gate     strcpy(*s,"<EMPTY>");
3217c478bd9Sstevel@tonic-gate   }else{
3227c478bd9Sstevel@tonic-gate     unsigned int length = asn1buf_len(buf);
3237c478bd9Sstevel@tonic-gate     int i;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate     *s = malloc(3*length);
3267c478bd9Sstevel@tonic-gate     if(*s == NULL) return ENOMEM;
3277c478bd9Sstevel@tonic-gate     for(i = length-1; i >= 0; i--){
3287c478bd9Sstevel@tonic-gate       (*s)[3*(length-i-1)] = hexchar(((buf->base)[i]&0xF0)>>4);
3297c478bd9Sstevel@tonic-gate       (*s)[3*(length-i-1)+1] = hexchar((buf->base)[i]&0x0F);
3307c478bd9Sstevel@tonic-gate       (*s)[3*(length-i-1)+2] = ' ';
3317c478bd9Sstevel@tonic-gate     }
3327c478bd9Sstevel@tonic-gate     (*s)[3*length-1] = '\0';
3337c478bd9Sstevel@tonic-gate   }
3347c478bd9Sstevel@tonic-gate   return 0;
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate /****************************************************************/
3387c478bd9Sstevel@tonic-gate /* Private Procedures */
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate #undef asn1buf_size
asn1buf_size(const asn1buf * buf)3417c478bd9Sstevel@tonic-gate int asn1buf_size(const asn1buf *buf)
3427c478bd9Sstevel@tonic-gate {
3437c478bd9Sstevel@tonic-gate   if(buf == NULL || buf->base == NULL) return 0;
3447c478bd9Sstevel@tonic-gate   return buf->bound - buf->base + 1;
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate #undef asn1buf_free
asn1buf_free(const asn1buf * buf)3487c478bd9Sstevel@tonic-gate int asn1buf_free(const asn1buf *buf)
3497c478bd9Sstevel@tonic-gate {
3507c478bd9Sstevel@tonic-gate   if(buf == NULL || buf->base == NULL) return 0;
3517c478bd9Sstevel@tonic-gate   else return buf->bound - buf->next + 1;
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate #undef asn1buf_ensure_space
asn1buf_ensure_space(asn1buf * buf,const unsigned int amount)3557c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_ensure_space(asn1buf *buf, const unsigned int amount)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate   int avail = asn1buf_free(buf);
3587c478bd9Sstevel@tonic-gate   if(avail < amount){
3597c478bd9Sstevel@tonic-gate     asn1_error_code retval = asn1buf_expand(buf, amount-avail);
3607c478bd9Sstevel@tonic-gate     if(retval) return retval;
3617c478bd9Sstevel@tonic-gate   }
3627c478bd9Sstevel@tonic-gate   return 0;
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
asn1buf_expand(asn1buf * buf,unsigned int inc)3657c478bd9Sstevel@tonic-gate asn1_error_code asn1buf_expand(asn1buf *buf, unsigned int inc)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate #define STANDARD_INCREMENT 200
3687c478bd9Sstevel@tonic-gate   int next_offset = buf->next - buf->base;
3697c478bd9Sstevel@tonic-gate   int bound_offset;
3707c478bd9Sstevel@tonic-gate   if (buf->base == NULL) bound_offset = -1;
3717c478bd9Sstevel@tonic-gate   else bound_offset = buf->bound - buf->base;
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate   if (inc < STANDARD_INCREMENT)
3747c478bd9Sstevel@tonic-gate     inc = STANDARD_INCREMENT;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate   if (buf->base == NULL)
3777c478bd9Sstevel@tonic-gate     buf->base = malloc((asn1buf_size(buf)+inc) * sizeof(asn1_octet));
3787c478bd9Sstevel@tonic-gate   else
3797c478bd9Sstevel@tonic-gate     buf->base = realloc(buf->base,
3807c478bd9Sstevel@tonic-gate 			(asn1buf_size(buf)+inc) * sizeof(asn1_octet));
3817c478bd9Sstevel@tonic-gate   if (buf->base == NULL) return ENOMEM;
3827c478bd9Sstevel@tonic-gate   buf->bound = (buf->base) + bound_offset + inc;
3837c478bd9Sstevel@tonic-gate   buf->next = (buf->base) + next_offset;
3847c478bd9Sstevel@tonic-gate   return 0;
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate #undef asn1buf_len
asn1buf_len(const asn1buf * buf)3887c478bd9Sstevel@tonic-gate int asn1buf_len(const asn1buf *buf)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate   return buf->next - buf->base;
3917c478bd9Sstevel@tonic-gate }
392