[xmlsec] separate asn1 parser



commit b8c085d337ccfa001362aab240d624349170af06
Author: Aleksey Sanin <aleksey aleksey com>
Date:   Mon May 10 19:00:55 2010 -0700

    separate asn1 parser

 src/gcrypt/Makefile.am |    2 +
 src/gcrypt/app.c       |  385 ++---------------------------------------
 src/gcrypt/asn1.c      |  451 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/gcrypt/asn1.h      |   34 ++++
 4 files changed, 504 insertions(+), 368 deletions(-)
---
diff --git a/src/gcrypt/Makefile.am b/src/gcrypt/Makefile.am
index 1c6d031..eba2835 100644
--- a/src/gcrypt/Makefile.am
+++ b/src/gcrypt/Makefile.am
@@ -20,6 +20,8 @@ libxmlsec1_gcrypt_la_CPPFLAGS = \
 
 libxmlsec1_gcrypt_la_SOURCES =\
 	app.c \
+	asn1.h \
+	asn1.c \
 	ciphers.c \
 	crypto.c \
 	digests.c \
diff --git a/src/gcrypt/app.c b/src/gcrypt/app.c
index 7643073..e1a7c64 100644
--- a/src/gcrypt/app.c
+++ b/src/gcrypt/app.c
@@ -20,371 +20,7 @@
 #include <xmlsec/gcrypt/app.h>
 #include <xmlsec/gcrypt/crypto.h>
 
-/**************************************************************************
- *
- * ASN.1 parser is taken from GCrypt tests
- *
- *************************************************************************/
-
-/* ASN.1 classes.  */
-enum
-{
-  UNIVERSAL = 0,
-  APPLICATION = 1,
-  ASNCONTEXT = 2,
-  PRIVATE = 3
-};
-
-
-/* ASN.1 tags.  */
-enum
-{
-  TAG_NONE = 0,
-  TAG_BOOLEAN = 1,
-  TAG_INTEGER = 2,
-  TAG_BIT_STRING = 3,
-  TAG_OCTET_STRING = 4,
-  TAG_NULL = 5,
-  TAG_OBJECT_ID = 6,
-  TAG_OBJECT_DESCRIPTOR = 7,
-  TAG_EXTERNAL = 8,
-  TAG_REAL = 9,
-  TAG_ENUMERATED = 10,
-  TAG_EMBEDDED_PDV = 11,
-  TAG_UTF8_STRING = 12,
-  TAG_REALTIVE_OID = 13,
-  TAG_SEQUENCE = 16,
-  TAG_SET = 17,
-  TAG_NUMERIC_STRING = 18,
-  TAG_PRINTABLE_STRING = 19,
-  TAG_TELETEX_STRING = 20,
-  TAG_VIDEOTEX_STRING = 21,
-  TAG_IA5_STRING = 22,
-  TAG_UTC_TIME = 23,
-  TAG_GENERALIZED_TIME = 24,
-  TAG_GRAPHIC_STRING = 25,
-  TAG_VISIBLE_STRING = 26,
-  TAG_GENERAL_STRING = 27,
-  TAG_UNIVERSAL_STRING = 28,
-  TAG_CHARACTER_STRING = 29,
-  TAG_BMP_STRING = 30
-};
-
-/* ASN.1 Parser object.  */
-struct tag_info
-{
-  int class;             /* Object class.  */
-  unsigned long tag;     /* The tag of the object.  */
-  unsigned long length;  /* Length of the values.  */
-  int nhdr;              /* Length of the header (TL).  */
-  unsigned int ndef:1;   /* The object has an indefinite length.  */
-  unsigned int cons:1;   /* This is a constructed object.  */
-};
-
-/* Parse the buffer at the address BUFFER which consists of the number
-   of octets as stored at BUFLEN.  Return the tag and the length part
-   from the TLV triplet.  Update BUFFER and BUFLEN on success.  Checks
-   that the encoded length does not exhaust the length of the provided
-   buffer. */
-static int
-parse_tag (xmlSecByte const **buffer, xmlSecSize *buflen, struct tag_info *ti)
-{
-  int c;
-  unsigned long tag;
-  const xmlSecByte *buf = *buffer;
-  xmlSecSize length = *buflen;
-
-  xmlSecAssert2(buffer != NULL, -1);
-  xmlSecAssert2((*buffer) != NULL, -1);
-  xmlSecAssert2(buflen != NULL, -1);
-  xmlSecAssert2(ti != NULL, -1);
-
-  ti->length = 0;
-  ti->ndef = 0;
-  ti->nhdr = 0;
-
-  /* Get the tag */
-  if (length <= 0) {
-    return(-1); /* Premature EOF.  */
-  }
-  c = *buf++; 
-  length--;
-  ti->nhdr++;
-
-  ti->class = (c & 0xc0) >> 6;
-  ti->cons  = !!(c & 0x20);
-  tag       = (c & 0x1f);
-
-  if (tag == 0x1f) {
-      tag = 0;
-      do {
-          tag <<= 7;
-          if (length <= 0) {
-            return(-1); /* Premature EOF.  */
-          }
-          c = *buf++; 
-          length--;
-          ti->nhdr++;
-          tag |= (c & 0x7f);
-      } while ( (c & 0x80) );
-  }
-  ti->tag = tag;
-
-  /* Get the length */
-  if(length <= 0) {
-    return -1; /* Premature EOF. */
-  }
-  c = *buf++; 
-  length--;
-  ti->nhdr++;
-
-  if ( !(c & 0x80) ) {
-    ti->length = c;
-  } else if (c == 0x80) {
-    ti->ndef = 1;
-  } else if (c == 0xff) {
-    return -1; /* Forbidden length value.  */
-  } else {
-      xmlSecSize len = 0;
-      int count = c & 0x7f;
-
-      for (; count; count--) {
-          len <<= 8;
-          if (length <= 0) {
-            return -1; /* Premature EOF.  */
-          }
-          c = *buf++; length--;
-          ti->nhdr++;
-          len |= (c & 0xff);
-      }
-      ti->length = len;
-    }
-
-  if (ti->class == UNIVERSAL && !ti->tag) {
-    ti->length = 0;\
-  }
-
-  if (ti->length > length) {
-    return(-1); /* Data larger than buffer.  */
-  }
-
-  *buffer = buf;
-  *buflen = length;
-  return(0);
-}
-
-static xmlSecKeyDataPtr
-read_private_key_file (const xmlSecByte * der, xmlSecSize derlen) {
-  xmlSecKeyDataPtr key_data = NULL;
-  gcry_sexp_t s_key = NULL;
-  gcry_error_t err;
-  struct tag_info ti;
-  gcry_mpi_t keyparms[8] = {
-    NULL, NULL, NULL, NULL,
-    NULL, NULL, NULL, NULL
-  } ;
-  int n_keyparms = 8;
-  int idx;
-  int ret;
-
-  /* Parse the ASN.1 structure.  */
-  if(parse_tag (&der, &derlen, &ti)
-       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
-  {
-    printf("ERROR - TODO: invalid ASN.1 structure\n");
-    goto done;
-  }
-
-  if (parse_tag (&der, &derlen, &ti)
-       || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef)
-  {
-    printf("ERROR - TODO: invalid ASN.1 structure\n");
-    goto done;
-  }
-
-  if (ti.length != 1 || *der) {
-    /* The value of the first integer is no 0. */
-    printf("ERROR - TODO: invalid ASN.1 structure\n");
-    goto done;
-  }
-  der += ti.length; derlen -= ti.length;
-
-  for (idx=0; idx < n_keyparms; idx++) {
-      if ( parse_tag (&der, &derlen, &ti)
-           || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef)
-      {
-        printf("ERROR - TODO: invalid ASN.1 structure\n");
-        goto done;
-      }
-
-      err = gcry_mpi_scan (keyparms+idx, GCRYMPI_FMT_USG, der, ti.length,NULL);
-      if (err) {
-        printf("ERROR - TODO\n");
-        goto done;
-      }
-      der += ti.length;
-      derlen -= ti.length;
-  }
-  if (idx != n_keyparms) {
-    /* die ("not enough RSA key parameters\n"); */
-    printf("ERROR - TODO\n");
-    goto done;
-  }
-
-  /* Convert from OpenSSL parameter ordering to the OpenPGP order. */
-  /* First check that p < q; if not swap p and q and recompute u.  */ 
-  if (gcry_mpi_cmp (keyparms[3], keyparms[4]) > 0) {
-      gcry_mpi_swap (keyparms[3], keyparms[4]);
-      gcry_mpi_invm (keyparms[7], keyparms[3], keyparms[4]);
-  }
-
-  /* Build the S-expression.  */
-  err = gcry_sexp_build (&s_key, NULL,
-                         "(key-data"
-                         "(public-key(rsa(n%m)(e%m)))"
-                         "(private-key(rsa(n%m)(e%m)"
-                         /**/            "(d%m)(p%m)(q%m)(u%m)))"
-                         ")",
-                         keyparms[0], keyparms[1],
-                         keyparms[0], keyparms[1],
-                         keyparms[2], keyparms[3], keyparms[4], keyparms[7]
-  );
-  if (err) {
-    /* die ("error building S-expression: %s\n", gpg_strerror (err)); */
-    printf("ERROR - TODO\n");
-    goto done;
-  }
-
-  key_data = xmlSecKeyDataCreate(xmlSecGCryptKeyDataRsaId);
-  if(key_data == NULL) {
-    xmlSecError(XMLSEC_ERRORS_HERE,
-                NULL,
-                "xmlSecKeyDataCreate",
-                XMLSEC_ERRORS_R_XMLSEC_FAILED,
-                "xmlSecGCryptKeyDataRsaId");
-    goto done;
-  }
-
-  ret = xmlSecGCryptKeyDataRsaAdoptKey(key_data, s_key);
-  if(ret < 0) {
-    xmlSecError(XMLSEC_ERRORS_HERE,
-                NULL,
-                "xmlSecGCryptKeyDataRsaAdoptKey",
-                XMLSEC_ERRORS_R_XMLSEC_FAILED,
-                "xmlSecGCryptKeyDataRsaId");
-    xmlSecKeyDataDestroy(key_data);
-    key_data = NULL;
-    goto done;
-  }
-  s_key = NULL; /* owned by key_data now */
-
-done:
-  if(s_key != NULL) {
-    gcry_sexp_release(s_key);
-  }
-  
-  for (idx=0; idx < n_keyparms; idx++) {
-    if(keyparms[idx] != NULL) {
-        gcry_mpi_release (keyparms[idx]);
-    }
-  }
-
-  return(key_data);
-}
-
-#if 0
-/* Read the file FNAME assuming it is a PEM encoded public key file
-   and return an S-expression.  With SHOW set, the key parameters are
-   printed.  */
-static gcry_sexp_t
-read_public_key_file (const char *fname, int show)
-{
-  gcry_error_t err;
-  FILE *fp;
-  char *buffer;
-  size_t buflen;
-  const unsigned char *der;
-  size_t derlen;
-  struct tag_info ti;
-  gcry_mpi_t keyparms[2];
-  int n_keyparms = 2;
-  int idx;
-  gcry_sexp_t s_key;
-
-  fp = fopen (fname, binary_input?"rb":"r");
-  if (!fp)
-    die ("can't open `%s': %s\n", fname, strerror (errno));
-  buffer = read_file (fp, 0, &buflen);
-  if (!buffer)
-    die ("error reading `%s'\n", fname);
-  fclose (fp);
-
-  buflen = base64_decode (buffer, buflen);
-  
-  /* Parse the ASN.1 structure.  */
-  der = (const unsigned char*)buffer;
-  derlen = buflen;
-  if ( parse_tag (&der, &derlen, &ti)
-       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
-    goto bad_asn1;
-  if ( parse_tag (&der, &derlen, &ti)
-       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
-    goto bad_asn1;
-  /* We skip the description of the key parameters and assume it is RSA.  */
-  der += ti.length; derlen -= ti.length;
-  
-  if ( parse_tag (&der, &derlen, &ti)
-       || ti.tag != TAG_BIT_STRING || ti.class || ti.cons || ti.ndef)
-    goto bad_asn1;
-  if (ti.length < 1 || *der)
-    goto bad_asn1;  /* The number of unused bits needs to be 0. */
-  der += 1; derlen -= 1;
-
-  /* Parse the BIT string.  */
-  if ( parse_tag (&der, &derlen, &ti)
-       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
-    goto bad_asn1;
-
-  for (idx=0; idx < n_keyparms; idx++)
-    {
-      if ( parse_tag (&der, &derlen, &ti)
-           || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef)
-        goto bad_asn1;
-      if (show)
-        {
-          char prefix[2];
-
-          prefix[0] = idx < 2? "ne"[idx] : '?';
-          prefix[1] = 0;
-          showhex (prefix, der, ti.length);
-        }
-      err = gcry_mpi_scan (keyparms+idx, GCRYMPI_FMT_USG, der, ti.length,NULL);
-      if (err)
-        die ("error scanning RSA parameter %d: %s\n", idx, gpg_strerror (err));
-      der += ti.length; derlen -= ti.length;
-    }
-  if (idx != n_keyparms)
-    die ("not enough RSA key parameters\n");
-
-  gcry_free (buffer);
-
-  /* Build the S-expression.  */
-  err = gcry_sexp_build (&s_key, NULL,
-                         "(public-key(rsa(n%m)(e%m)))",
-                         keyparms[0], keyparms[1] );
-  if (err)
-    die ("error building S-expression: %s\n", gpg_strerror (err));
-  
-  for (idx=0; idx < n_keyparms; idx++)
-    gcry_mpi_release (keyparms[idx]);
-  
-  return s_key;
-  
- bad_asn1:
-  die ("invalid ASN.1 structure in `%s'\n", fname);
-  return NULL; /*NOTREACHED*/
-}
-#endif /* 0 */
+#include "src/gcrypt/asn1.h"
 
 /**
  * xmlSecGCryptAppInit:
@@ -508,6 +144,17 @@ xmlSecGCryptAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize,
     xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL);
 
     switch(format) {
+    case xmlSecKeyDataFormatDer:
+        key_data = xmlSecGCryptParseDer(data, dataSize);
+        if(key_data == NULL) {
+            xmlSecError(XMLSEC_ERRORS_HERE,
+                        NULL,
+                        "xmlSecGCryptParseDer",
+                        XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                        XMLSEC_ERRORS_NO_MESSAGE);
+            return(NULL);
+        }
+        break;
     case xmlSecKeyDataFormatPem:
         xmlSecError(XMLSEC_ERRORS_HERE,
                     NULL,
@@ -515,9 +162,6 @@ xmlSecGCryptAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize,
                     XMLSEC_ERRORS_R_NOT_IMPLEMENTED,
                     XMLSEC_ERRORS_NO_MESSAGE);
         return (NULL);
-    case xmlSecKeyDataFormatDer:
-        key_data = read_private_key_file(data, dataSize);
-        break;
 #ifndef XMLSEC_NO_X509
     case xmlSecKeyDataFormatPkcs12:
         xmlSecError(XMLSEC_ERRORS_HERE,
@@ -536,6 +180,8 @@ xmlSecGCryptAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize,
         return(NULL);
     }
 
+    /* we should have key data by now */
+    xmlSecAssert2(key_data != NULL, -1);
     key = xmlSecKeyCreate();
     if(key == NULL) {
         xmlSecError(XMLSEC_ERRORS_HERE,
@@ -559,6 +205,9 @@ xmlSecGCryptAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize,
         xmlSecKeyDataDestroy(key_data);
         return(NULL);
     }
+    key_data = NULL; /* key_data is owned by key */
+
+    /* done */
     return(key);
 }
 
diff --git a/src/gcrypt/asn1.c b/src/gcrypt/asn1.c
new file mode 100644
index 0000000..95e7650
--- /dev/null
+++ b/src/gcrypt/asn1.c
@@ -0,0 +1,451 @@
+/**
+ * XMLSec library
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2002-2003 Aleksey Sanin <aleksey aleksey com>
+ */
+#include "globals.h"
+
+#include <string.h>
+
+#include <gcrypt.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/errors.h>
+
+#include <xmlsec/gcrypt/crypto.h>
+
+#include "src/gcrypt/asn1.h"
+
+/**************************************************************************
+ *
+ * ASN.1 parser is taken from GCrypt tests
+ *
+ *************************************************************************/
+
+/* ASN.1 classes.  */
+enum
+{
+  UNIVERSAL = 0,
+  APPLICATION = 1,
+  ASNCONTEXT = 2,
+  PRIVATE = 3
+};
+
+
+/* ASN.1 tags.  */
+enum
+{
+  TAG_NONE = 0,
+  TAG_BOOLEAN = 1,
+  TAG_INTEGER = 2,
+  TAG_BIT_STRING = 3,
+  TAG_OCTET_STRING = 4,
+  TAG_NULL = 5,
+  TAG_OBJECT_ID = 6,
+  TAG_OBJECT_DESCRIPTOR = 7,
+  TAG_EXTERNAL = 8,
+  TAG_REAL = 9,
+  TAG_ENUMERATED = 10,
+  TAG_EMBEDDED_PDV = 11,
+  TAG_UTF8_STRING = 12,
+  TAG_REALTIVE_OID = 13,
+  TAG_SEQUENCE = 16,
+  TAG_SET = 17,
+  TAG_NUMERIC_STRING = 18,
+  TAG_PRINTABLE_STRING = 19,
+  TAG_TELETEX_STRING = 20,
+  TAG_VIDEOTEX_STRING = 21,
+  TAG_IA5_STRING = 22,
+  TAG_UTC_TIME = 23,
+  TAG_GENERALIZED_TIME = 24,
+  TAG_GRAPHIC_STRING = 25,
+  TAG_VISIBLE_STRING = 26,
+  TAG_GENERAL_STRING = 27,
+  TAG_UNIVERSAL_STRING = 28,
+  TAG_CHARACTER_STRING = 29,
+  TAG_BMP_STRING = 30
+};
+
+/* ASN.1 Parser object.  */
+struct tag_info
+{
+  int class;             /* Object class.  */
+  unsigned long tag;     /* The tag of the object.  */
+  unsigned long length;  /* Length of the values.  */
+  int nhdr;              /* Length of the header (TL).  */
+  unsigned int ndef:1;   /* The object has an indefinite length.  */
+  unsigned int cons:1;   /* This is a constructed object.  */
+};
+
+/* Parse the buffer at the address BUFFER which consists of the number
+   of octets as stored at BUFLEN.  Return the tag and the length part
+   from the TLV triplet.  Update BUFFER and BUFLEN on success.  Checks
+   that the encoded length does not exhaust the length of the provided
+   buffer. */
+static int
+xmlSecGCryptAsn1ParseTag (xmlSecByte const **buffer, xmlSecSize *buflen, struct tag_info *ti)
+{
+    int c;
+    unsigned long tag;
+    const xmlSecByte *buf = *buffer;
+    xmlSecSize length = *buflen;
+
+    xmlSecAssert2(buffer != NULL, -1);
+    xmlSecAssert2((*buffer) != NULL, -1);
+    xmlSecAssert2(buflen != NULL, -1);
+    xmlSecAssert2(ti != NULL, -1);
+
+    ti->length = 0;
+    ti->ndef = 0;
+    ti->nhdr = 0;
+
+    /* Get the tag */
+    if (length <= 0) {
+        return(-1); /* Premature EOF.  */
+    }
+    c = *buf++; 
+    length--;
+    ti->nhdr++;
+
+    ti->class = (c & 0xc0) >> 6;
+    ti->cons  = !!(c & 0x20);
+    tag       = (c & 0x1f);
+
+    if (tag == 0x1f) {
+        tag = 0;
+        do {
+            tag <<= 7;
+            if (length <= 0) {
+                return(-1); /* Premature EOF.  */
+            }
+            c = *buf++; 
+            length--;
+            ti->nhdr++;
+            tag |= (c & 0x7f);
+        } while ( (c & 0x80) );
+    }
+    ti->tag = tag;
+
+    /* Get the length */
+    if(length <= 0) {
+        return -1; /* Premature EOF. */
+    }
+    c = *buf++; 
+    length--;
+    ti->nhdr++;
+
+    if ( !(c & 0x80) ) {
+        ti->length = c;
+    } else if (c == 0x80) {
+        ti->ndef = 1;
+    } else if (c == 0xff) {
+        return -1; /* Forbidden length value.  */
+    } else {
+        xmlSecSize len = 0;
+        int count = c & 0x7f;
+
+        for (; count; count--) {
+            len <<= 8;
+            if (length <= 0) {
+                return -1; /* Premature EOF.  */
+            }
+            c = *buf++; length--;
+            ti->nhdr++;
+            len |= (c & 0xff);
+        }
+        ti->length = len;
+    }
+
+    if (ti->class == UNIVERSAL && !ti->tag) {
+        ti->length = 0;
+    }
+
+    if (ti->length > length) {
+        return(-1); /* Data larger than buffer.  */
+    }
+
+    /* done */
+    *buffer = buf;
+    *buflen = length;
+    return(0);
+}
+
+xmlSecKeyDataPtr
+xmlSecGCryptParseDerPrivateKey(const xmlSecByte * der, xmlSecSize derlen) {
+    xmlSecKeyDataPtr key_data = NULL;
+    gcry_sexp_t s_key = NULL;
+    gcry_error_t err;
+    struct tag_info ti;
+    gcry_mpi_t keyparms[8] = {
+        NULL, NULL, NULL, NULL,
+        NULL, NULL, NULL, NULL
+    } ;
+    int n_keyparms = sizeof(keyparms) / sizeof(keyparms[0]);
+    int idx;
+    int ret;
+
+    xmlSecAssert2(der != NULL, NULL);
+    xmlSecAssert2(derlen > 0, NULL);
+
+    /* Parse the ASN.1 structure.  */
+    if(xmlSecGCryptAsn1ParseTag (&der, &derlen, &ti)
+       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
+    {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "xmlSecGCryptAsn1ParseTag",
+                    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                    "TAG_SEQUENCE is expected");
+        goto done;
+    }
+
+    if (xmlSecGCryptAsn1ParseTag (&der, &derlen, &ti)
+       || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef)
+    {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "xmlSecGCryptAsn1ParseTag",
+                    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                    "TAG_INTEGER is expected");
+        goto done;
+    }
+
+    if ((ti.length != 1) || ((*der) != 0)) {
+        /* The value of the first integer is no 0. */
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "xmlSecGCryptAsn1ParseTag",
+                    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                    "integer length=%d, value=%d",
+                    (int)ti.length, (int)(*der));
+        goto done;
+    }
+    der += ti.length; 
+    derlen -= ti.length;
+
+    /* read params */
+    for (idx=0; idx < n_keyparms; idx++) {
+        if ( xmlSecGCryptAsn1ParseTag (&der, &derlen, &ti)
+           || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef)
+        {
+            xmlSecError(XMLSEC_ERRORS_HERE,
+                        NULL,
+                        "xmlSecGCryptAsn1ParseTag",
+                        XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                        "TAG_INTEGER is expected - index=%d",
+                        (int)idx);
+            goto done;
+        }
+
+        err = gcry_mpi_scan (keyparms+idx, GCRYMPI_FMT_USG, der, ti.length,NULL);
+        if (err) {
+            xmlSecError(XMLSEC_ERRORS_HERE,
+                        NULL,
+                        "gcry_mpi_scan",
+                        XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                        "err=%d", (int)err);
+            goto done;
+        }
+        der += ti.length;
+        derlen -= ti.length;
+    }
+
+    if (idx != n_keyparms) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "xmlSecGCryptAsn1ParseTag",
+                    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                    "Not enough params: index=%d, expected=%d",
+                    (int)idx, (int)n_keyparms);
+        goto done;
+    }
+
+    /* Convert from OpenSSL parameter ordering to the OpenPGP order. */
+    /* First check that p < q; if not swap p and q and recompute u.  */ 
+    if (gcry_mpi_cmp (keyparms[3], keyparms[4]) > 0) {
+        gcry_mpi_swap (keyparms[3], keyparms[4]);
+        gcry_mpi_invm (keyparms[7], keyparms[3], keyparms[4]);
+    }
+
+    /* Build the S-expression.  */
+    err = gcry_sexp_build (&s_key, NULL,
+                         "(key-data"
+                         "(public-key(rsa(n%m)(e%m)))"
+                         "(private-key(rsa(n%m)(e%m)"
+                         /**/            "(d%m)(p%m)(q%m)(u%m)))"
+                         ")",
+                         keyparms[0], keyparms[1],
+                         keyparms[0], keyparms[1],
+                         keyparms[2], keyparms[3], keyparms[4], keyparms[7]
+    );
+    if (err) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "gcry_sexp_build",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "err=%d", (int)err);
+        goto done;
+    }
+
+    key_data = xmlSecKeyDataCreate(xmlSecGCryptKeyDataRsaId);
+    if(key_data == NULL) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "xmlSecKeyDataCreate",
+                    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                    "xmlSecGCryptKeyDataRsaId");
+        goto done;
+    }
+
+    ret = xmlSecGCryptKeyDataRsaAdoptKey(key_data, s_key);
+    if(ret < 0) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "xmlSecGCryptKeyDataRsaAdoptKey",
+                    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                    "xmlSecGCryptKeyDataRsaId");
+        xmlSecKeyDataDestroy(key_data);
+        key_data = NULL;
+        goto done;
+    }
+    s_key = NULL; /* owned by key_data now */
+
+done:
+    if(s_key != NULL) {
+        gcry_sexp_release(s_key);
+    }
+
+    for (idx=0; idx < n_keyparms; idx++) {
+        if(keyparms[idx] != NULL) {
+            gcry_mpi_release (keyparms[idx]);
+        }
+    }
+
+    return(key_data);
+}
+
+
+xmlSecKeyDataPtr
+xmlSecGCryptParseDerPublicKey(const xmlSecByte * der, xmlSecSize derlen) {
+    xmlSecAssert2(der != NULL, NULL);
+    xmlSecAssert2(derlen > 0, NULL);
+
+    /* aleksey todo */
+    return(NULL);
+}
+
+#if 0
+/* Read the file FNAME assuming it is a PEM encoded public key file
+   and return an S-expression.  With SHOW set, the key parameters are
+   printed.  */
+static gcry_sexp_t
+read_public_key_file (const char *fname, int show)
+{
+  gcry_error_t err;
+  FILE *fp;
+  char *buffer;
+  size_t buflen;
+  const unsigned char *der;
+  size_t derlen;
+  struct tag_info ti;
+  gcry_mpi_t keyparms[2];
+  int n_keyparms = 2;
+  int idx;
+  gcry_sexp_t s_key;
+
+  fp = fopen (fname, binary_input?"rb":"r");
+  if (!fp)
+    die ("can't open `%s': %s\n", fname, strerror (errno));
+  buffer = read_file (fp, 0, &buflen);
+  if (!buffer)
+    die ("error reading `%s'\n", fname);
+  fclose (fp);
+
+  buflen = base64_decode (buffer, buflen);
+  
+  /* Parse the ASN.1 structure.  */
+  der = (const unsigned char*)buffer;
+  derlen = buflen;
+  if ( xmlSecGCryptAsn1ParseTag (&der, &derlen, &ti)
+       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
+    goto bad_asn1;
+  if ( xmlSecGCryptAsn1ParseTag (&der, &derlen, &ti)
+       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
+    goto bad_asn1;
+  /* We skip the description of the key parameters and assume it is RSA.  */
+  der += ti.length; derlen -= ti.length;
+  
+  if ( xmlSecGCryptAsn1ParseTag (&der, &derlen, &ti)
+       || ti.tag != TAG_BIT_STRING || ti.class || ti.cons || ti.ndef)
+    goto bad_asn1;
+  if (ti.length < 1 || *der)
+    goto bad_asn1;  /* The number of unused bits needs to be 0. */
+  der += 1; derlen -= 1;
+
+  /* Parse the BIT string.  */
+  if ( xmlSecGCryptAsn1ParseTag (&der, &derlen, &ti)
+       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
+    goto bad_asn1;
+
+  for (idx=0; idx < n_keyparms; idx++)
+    {
+      if ( xmlSecGCryptAsn1ParseTag (&der, &derlen, &ti)
+           || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef)
+        goto bad_asn1;
+      if (show)
+        {
+          char prefix[2];
+
+          prefix[0] = idx < 2? "ne"[idx] : '?';
+          prefix[1] = 0;
+          showhex (prefix, der, ti.length);
+        }
+      err = gcry_mpi_scan (keyparms+idx, GCRYMPI_FMT_USG, der, ti.length,NULL);
+      if (err)
+        die ("error scanning RSA parameter %d: %s\n", idx, gpg_strerror (err));
+      der += ti.length; derlen -= ti.length;
+    }
+  if (idx != n_keyparms)
+    die ("not enough RSA key parameters\n");
+
+  gcry_free (buffer);
+
+  /* Build the S-expression.  */
+  err = gcry_sexp_build (&s_key, NULL,
+                         "(public-key(rsa(n%m)(e%m)))",
+                         keyparms[0], keyparms[1] );
+  if (err)
+    die ("error building S-expression: %s\n", gpg_strerror (err));
+  
+  for (idx=0; idx < n_keyparms; idx++)
+    gcry_mpi_release (keyparms[idx]);
+  
+  return s_key;
+  
+ bad_asn1:
+  die ("invalid ASN.1 structure in `%s'\n", fname);
+  return NULL; /*NOTREACHED*/
+}
+#endif /* 0 */
+
+
+xmlSecKeyDataPtr
+xmlSecGCryptParseDer(const xmlSecByte * der, xmlSecSize derlen) {
+    xmlSecKeyDataPtr res = NULL;
+
+    xmlSecAssert2(der != NULL, NULL);
+    xmlSecAssert2(derlen > 0, NULL);
+
+    /* try private key first */
+    res = xmlSecGCryptParseDerPrivateKey(der, derlen);
+    if(res == NULL) {
+        res = xmlSecGCryptParseDerPublicKey(der, derlen);
+    }
+
+    return(res);
+}
+
diff --git a/src/gcrypt/asn1.h b/src/gcrypt/asn1.h
new file mode 100644
index 0000000..47af8ac
--- /dev/null
+++ b/src/gcrypt/asn1.h
@@ -0,0 +1,34 @@
+/*
+ * XML Security Library
+ *
+ * gcrypt/asn1.h: internal header only used during the compilation
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2010 Aleksey Sanin <aleksey aleksey com>
+ */
+#ifndef __XMLSEC_GCRYPT_ASN1_H__
+#define __XMLSEC_GCRYPT_ASN1_H__
+
+#ifndef XMLSEC_PRIVATE
+#error "gcrypt/asn1.h file contains private xmlsec-gcrypt definitions and should not be used outside xmlsec or xmlsec-<crypto> libraries"
+#endif /* XMLSEC_PRIVATE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+xmlSecKeyDataPtr        xmlSecGCryptParseDerPrivateKey  (const xmlSecByte * der,
+                                                         xmlSecSize derlen);
+xmlSecKeyDataPtr        xmlSecGCryptParseDerPublicKey   (const xmlSecByte * der,
+                                                         xmlSecSize derlen);
+xmlSecKeyDataPtr        xmlSecGCryptParseDer            (const xmlSecByte * der,
+                                                         xmlSecSize derlen);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /*__XMLSEC_GCRYPT_ASN1_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]