New SILC PKCS API, enabling support for other public keys/certs.
[crypto.git] / lib / silcasn1 / silcasn1_encode.c
index 7c8d667d3dd64028ba4f22b6080e9d2898d2b401..d8706b73a9dbd31643d3a0c99913a63cea5f0ac9 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcasn1.h"
 #include "silcber.h"
 
@@ -91,12 +91,19 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
     indef = (opts & SILC_ASN1_INDEFINITE ? TRUE : FALSE);
 
     /* By default UNIVERSAL is implied unless the following conditions
-       are met when CONTEXT will apply. */
+       are met when CONTEXT will apply.  For SILC_ASN1_TAG_ANY_PRIMITIVE
+       the class is changed only if flags dictate it. */
     if (ber_class == SILC_BER_CLASS_UNIVERSAL) {
-      if (tag != type ||
-         opts & SILC_ASN1_IMPLICIT ||
-         opts & SILC_ASN1_EXPLICIT)
-       ber_class = SILC_BER_CLASS_CONTEXT;
+      if (type == SILC_ASN1_TAG_ANY_PRIMITIVE) {
+       if (opts & SILC_ASN1_IMPLICIT ||
+           opts & SILC_ASN1_EXPLICIT)
+         ber_class = SILC_BER_CLASS_CONTEXT;
+      } else {
+       if (tag != type ||
+           opts & SILC_ASN1_IMPLICIT ||
+           opts & SILC_ASN1_EXPLICIT)
+         ber_class = SILC_BER_CLASS_CONTEXT;
+      }
     }
 
 #ifdef SILC_DEBUG
@@ -192,11 +199,31 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
          len = silc_buffer_len(node);
          dest = silc_buffer_srealloc_size(stack1, dest,
                                           silc_buffer_truelen(dest) + len);
+         if (!dest)
+           goto fail;
          silc_buffer_put(dest, node->data, len);
        }
        break;
       }
 
+    case SILC_ASN1_TAG_ANY_PRIMITIVE:
+      {
+       /* ANY_PRIMITIVE is any primitive in encoded format. */
+       SilcBuffer prim = va_arg(asn1->ap, SilcBuffer);
+       if (!prim)
+         break;
+
+       /* Encode the primitive data */
+       len = silc_ber_encoded_len(tag, silc_buffer_len(prim), FALSE);
+       dest = silc_buffer_srealloc_size(stack1, dest,
+                                        silc_buffer_truelen(dest) + len);
+       ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
+                             tag, prim->data, silc_buffer_len(prim), FALSE);
+       if (!ret)
+         goto fail;
+       break;
+      }
+
     case SILC_ASN1_TAG_SEQUENCE:
     case SILC_ASN1_TAG_SET:
       {
@@ -241,11 +268,15 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
             bytes in 1s complement */
        } else {
          /* Positive */
-         len = (silc_mp_sizeinbase(mpint, 2) + 7) / 8;
-         len += len & 7 ? 1: 0;
+         len = silc_mp_sizeinbase(mpint, 2);
+         if (!(len & 7))
+           len = ((len + 7) / 8) + 1;
+         else
+           len = (len + 7) / 8;
          silc_stack_push(stack2, &frame);
          silc_buffer_srealloc_size(stack2, &buf,
                                    silc_buffer_truelen(&buf) + len);
+         buf.data[0] = 0x00;
          silc_mp_mp2bin_noalloc(mpint, buf.data, silc_buffer_len(&buf));
        }