encoding public EC keys is not really possible without subjectPublicKeyInfo
authorMartin Willi <martin@strongswan.org>
Wed, 26 Aug 2009 14:15:38 +0000 (16:15 +0200)
committerMartin Willi <martin@strongswan.org>
Wed, 26 Aug 2009 14:15:38 +0000 (16:15 +0200)
src/libstrongswan/credentials/keys/key_encoding.h
src/libstrongswan/plugins/openssl/openssl_util.c
src/pki/pki.c

index 27a120e..a338f07 100644 (file)
@@ -72,9 +72,11 @@ enum key_encoding_type_t {
        /** PGPv4 fingerprint */
        KEY_ID_PGPV4,
        
-       /** PKCS#1/ASN.1 key encoding */
+       /** PKCS#1 and similar ASN.1 key encoding */
        KEY_PUB_ASN1_DER,
        KEY_PRIV_ASN1_DER,
+       /** subjectPublicKeyInfo encoding */
+       KEY_PUB_SPKI_ASN1_DER,
        /** PEM oncoded PKCS#1 key */
        KEY_PUB_PEM,
        KEY_PRIV_PEM,
index 67b7327..60b4e74 100644 (file)
@@ -125,9 +125,39 @@ bool openssl_bn_split(chunk_t chunk, BIGNUM *a, BIGNUM *b)
 }
 
 /**
+ * wrap publicKey in subjectPublicKeyInfo
+ */
+static chunk_t build_info(chunk_t key)
+{
+       X509_PUBKEY *pubkey;
+       chunk_t enc;
+       u_char *p;
+       
+       pubkey = X509_PUBKEY_new();
+       ASN1_OBJECT_free(pubkey->algor->algorithm);
+       pubkey->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption);
+
+       if (pubkey->algor->parameter == NULL ||
+               pubkey->algor->parameter->type != V_ASN1_NULL)
+       {
+               ASN1_TYPE_free(pubkey->algor->parameter);
+               pubkey->algor->parameter = ASN1_TYPE_new();
+               pubkey->algor->parameter->type = V_ASN1_NULL;
+       }
+       M_ASN1_BIT_STRING_set(pubkey->public_key, key.ptr, key.len);
+       
+       enc = chunk_alloc(i2d_X509_PUBKEY(pubkey, NULL));
+       p = enc.ptr;
+       i2d_X509_PUBKEY(pubkey, &p);
+       X509_PUBKEY_free(pubkey);
+       
+       return enc;
+}
+
+/**
  * Build fingerprints of a private/public RSA key.
  */
-static bool build_fingerprint(chunk_t key, key_encoding_type_t type, int nid,
+static bool build_fingerprint(chunk_t key, key_encoding_type_t type,
                                                          chunk_t *fingerprint)
 {
        hasher_t *hasher;
@@ -140,29 +170,9 @@ static bool build_fingerprint(chunk_t key, key_encoding_type_t type, int nid,
        }
        if (type == KEY_ID_PUBKEY_INFO_SHA1)
        {
-               X509_PUBKEY *pubkey;
                chunk_t enc;
-               u_char *p;
-               
-               /* wrap publicKey in subjectPublicKeyInfo */
-               pubkey = X509_PUBKEY_new();
-               ASN1_OBJECT_free(pubkey->algor->algorithm);
-               pubkey->algor->algorithm = OBJ_nid2obj(nid);
-       
-               if (pubkey->algor->parameter == NULL ||
-                       pubkey->algor->parameter->type != V_ASN1_NULL)
-               {
-                       ASN1_TYPE_free(pubkey->algor->parameter);
-                       pubkey->algor->parameter = ASN1_TYPE_new();
-                       pubkey->algor->parameter->type = V_ASN1_NULL;
-               }
-               M_ASN1_BIT_STRING_set(pubkey->public_key, enc.ptr, enc.len);
-               
-               enc = chunk_alloc(i2d_X509_PUBKEY(pubkey, NULL));
-               p = enc.ptr;
-               i2d_X509_PUBKEY(pubkey, &p);
-               X509_PUBKEY_free(pubkey);
                
+               enc = build_info(key);
                hasher->allocate_hash(hasher, enc, fingerprint);
                chunk_free(&enc);
        }
@@ -184,11 +194,27 @@ bool openssl_encode(key_encoding_type_t type, chunk_t *encoding, va_list args)
        switch (type)
        {
                case KEY_PUB_ASN1_DER:
+                       /* this encoding is currently not supported for ECDSA keys */
+                       if (key_encoding_args(args, KEY_PART_RSA_PUB_ASN1_DER, &key,
+                                                                 KEY_PART_END))
+                       {
+                               *encoding = chunk_clone(key);
+                               return TRUE;
+                       }
+                       return FALSE;
+               case KEY_PUB_SPKI_ASN1_DER:
+                       /* key encoding, wrapped in a subjectPublicKeyInfo field */
                        if (key_encoding_args(args, KEY_PART_RSA_PUB_ASN1_DER, &key,
-                                                                 KEY_PART_END) ||
-                               key_encoding_args(args, KEY_PART_ECDSA_PUB_ASN1_DER, &key,
                                                                  KEY_PART_END))
                        {
+                               *encoding = build_info(key);
+                               return TRUE;
+                       }
+                       else if (key_encoding_args(args, KEY_PART_ECDSA_PUB_ASN1_DER, &key,
+                                                                          KEY_PART_END))
+                       {
+                               /* ECDSA keys are already wrapped in the publickeyInfo field,
+                                * they are incomplete without */
                                *encoding = chunk_clone(key);
                                return TRUE;
                        }
@@ -208,13 +234,13 @@ bool openssl_encode(key_encoding_type_t type, chunk_t *encoding, va_list args)
                        if (key_encoding_args(args, KEY_PART_RSA_PUB_ASN1_DER, &key,
                                                                  KEY_PART_END))
                        {
-                               return build_fingerprint(key, type, NID_rsaEncryption, encoding);
+                               return build_fingerprint(key, type, encoding);
                        }
                        else if (key_encoding_args(args, KEY_PART_ECDSA_PUB_ASN1_DER, &key,
                                                                           KEY_PART_END))
                        {
-                               return build_fingerprint(key, type, NID_X9_62_id_ecPublicKey,
-                                                                                encoding);
+                               /* for ECDSA the two keyids are currently the same */
+                               return build_fingerprint(key, KEY_ID_PUBKEY_SHA1, encoding);
                        }
                        return FALSE;
                default:
index 9628351..1d15094 100644 (file)
@@ -43,7 +43,7 @@ static int usage(char *error)
        fprintf(out, "      show this usage information\n");
        fprintf(out, "  pki --gen [--type rsa|ecdsa] [--size bits] [--form der|pem|pgp]\n");
        fprintf(out, "      generate a new private key\n");
-       fprintf(out, "  pki --pub [--type rsa|ecdsa|x509] [--form der|pem|pgp]\n");
+       fprintf(out, "  pki --pub [--in file] [--type rsa|ecdsa|x509] [--form der|pem|pgp]\n");
        fprintf(out, "      extract the public key from a private key/certificate\n");
        return !!error;
 }
@@ -55,7 +55,8 @@ static bool get_form(char *form, key_encoding_type_t *type, bool pub)
 {
        if (streq(form, "der"))
        {
-               *type = pub ? KEY_PUB_ASN1_DER : KEY_PRIV_ASN1_DER;
+               /* der encoded keys usually contain the complete SubjectPublicKeyInfo */
+               *type = pub ? KEY_PUB_SPKI_ASN1_DER : KEY_PRIV_ASN1_DER;
        }
        else if (streq(form, "pem"))
        {
@@ -171,17 +172,20 @@ static int gen(int argc, char *argv[])
  */
 static int pub(int argc, char *argv[])
 {
-       key_encoding_type_t form = KEY_PUB_ASN1_DER;
+       key_encoding_type_t form = KEY_PUB_SPKI_ASN1_DER;
        credential_type_t type = CRED_PRIVATE_KEY;
        int subtype = KEY_RSA;
        certificate_t *cert;
        private_key_t *private;
        public_key_t *public;
        chunk_t encoding;
+       char *file = NULL;
+       void *cred;
        
        struct option long_opts[] = {
                { "type", required_argument, NULL, 't' },
                { "form", required_argument, NULL, 'f' },
+               { "in", required_argument, NULL, 'i' },
                { 0,0,0,0 }
        };
        while (TRUE)
@@ -215,6 +219,9 @@ static int pub(int argc, char *argv[])
                                        return usage("invalid output format");
                                }
                                continue;
+                       case 'i':
+                               file = optarg;
+                               continue;
                        case EOF:
                                break;
                        default:
@@ -222,13 +229,23 @@ static int pub(int argc, char *argv[])
                }
                break;
        }
-       if (type == CRED_PRIVATE_KEY)
+       if (file)
+       {
+               cred = lib->creds->create(lib->creds, type, subtype,
+                                                                        BUILD_FROM_FILE, file, BUILD_END);
+       }
+       else
        {
-               private = lib->creds->create(lib->creds, type, subtype,
+               cred = lib->creds->create(lib->creds, type, subtype,
                                                                         BUILD_FROM_FD, 0, BUILD_END);
+       }
+       
+       if (type == CRED_PRIVATE_KEY)
+       {
+               private = cred;
                if (!private)
                {
-                       fprintf(stderr, "parsing private key failed");
+                       fprintf(stderr, "parsing private key failed\n");
                        return 1;
                }
                public = private->get_public_key(private);
@@ -236,11 +253,10 @@ static int pub(int argc, char *argv[])
        }
        else
        {
-               cert = lib->creds->create(lib->creds, type, subtype,
-                                                                 BUILD_FROM_FD, 0, BUILD_END);
+               cert = cred;
                if (!cert)
                {
-                       fprintf(stderr, "parsing certificate failed");
+                       fprintf(stderr, "parsing certificate failed\n");
                        return 1;
                }
                public = cert->get_public_key(cert);