What is needed to convert ASN.1 data to a Public Key? e.g. how do I determine the OID?
Asked Answered
S

2

4

This code relates to DKIM signature verification used in anti-spam efforts.

I have a byte[] from s1024._domainkey.yahoo.com that is ASN.1 encoded, but I don't know if that alone contains enough information to materialize a public key.

Based on this class, it appears I can convert an ASN.1 key into a X509Certificate Public key, but I need to supply an OID and some ASN.1-encoded parameters.

In this example I have metadata that the ASN1 key is:

  1. An RSA encoded key (ASN.1 DER-encoded [ITU-X660-1997] RSAPublicKey per RFC3447)
  2. Used with either sha1 sha256 hash algorithms
  3. Uses an OID relating to the following table from section A.2 of RFC3447 (though I don't know how to turn this information into a full OID)
/*
 * 1.2.840.113549.1
 * 
    MD2 md2WithRSAEncryption    ::= {pkcs-1 2}
    MD5 md5WithRSAEncryption    ::= {pkcs-1 4}
    SHA-1 sha1WithRSAEncryption   ::= {pkcs-1 5}
    SHA-256 sha256WithRSAEncryption ::= {pkcs-1 11}
    SHA-384 sha384WithRSAEncryption ::= {pkcs-1 12}
    SHA-512 sha512WithRSAEncryption ::= {pkcs-1 13}
 */

Code sample

string pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB";
byte[] pubkeyByteArray = Convert.FromBase64String(pubkey);
AsnEncodedData aData = new AsnEncodedData(pubkeyByteArray);

// OID must not be null, but it is here.  What is it?
System.Security.Cryptography.X509Certificates.PublicKey pubKeyRdr = new System.Security.Cryptography.X509Certificates.PublicKey(aData.Oid, null, aData);

Question

  • What OID should I use?
  • What are examples of ASN.1 parameters?
Shipment answered 29/6, 2012 at 21:16 Comment(2)
It doesn't seem like AsnEncodedData actually parses the data. You'll have to set the oid through, aData.Oid = new Oid("1.2.840.113549.1.1"). After parsing the DER-TLV, you can use oid tool to convert the hex data to string representation, UNIVERSAL OID.1.2.840.113549.1.1.1.Souse
Here's a related question that deals with just the key, a CspParameters and RSACryptoServiceProvider: Load ASN.1/DER encoded RSA keypair in C#. I point it out because so many Stack overflow answers tell you do things with certificates or use BouncyCastle when all you are doing is trying to load a key. Also note... the pain point is due to .Net and their use of XML encoding from RFC 3275. .Net does not accept ASN.1/DER or PEM encoded keys.Spleenful
S
6

Update

This is the data you have provided when it is parsed using the link @erickson provided:

SEQUENCE (2 elem)
    SEQUENCE (2 elem)
        OBJECT IDENTIFIER 1.2.840.113549.1.1.1
        NULL
    BIT STRING (1 elem)
        SEQUENCE (2 elem)
            INTEGER(1024 bit)
            INTEGER 65537

The reason the previous code throws a ASN1 bad tag value met. exception is because aData contains incorrect data (contains all the data above). From what I've seen, the is how the 3 arguments to System.Security.Cryptography.X509Certificates.PublicKey are broken down.

  1. The first parameter is the OID, which is the OBJECT IDENTIFIER above.
  2. The second parameter is the public key parameters. In the parsing above, you can see it is NULL.
  3. The third parameter is actual public key value. This is made up of the third sequence above. The sequence has 2 integers, a 1024-bit modulus followed by the public exponent.

I tested it using the code below. I couldn't find a built-in method to parse the data without writing a DER parser.

Oid oid = new Oid("1.2.840.113549.1.1.1");
AsnEncodedData keyValue = new AsnEncodedData(getBytes("30818902818100EB11E7B4462E09BB3F907E2598BA2FC4F541925DABBFD8FF0B8E74C3F15E149E7FB6140655184DE42F6DDBCDEA142D8BF83DE95E07781F98988324E294DCDB392F82890145078C5C0379BB7434FFAC04AD1529E4C04CBD98AFF4B76D3FF1872FB5C6D8F8464755EDF5714E7E7A2DBE2E7549F0BB12B85796F93DD38A8FFF97730203010001"));
AsnEncodedData keyParam = new AsnEncodedData(new byte[] {05, 00});
PublicKey pubKeyRdr = new System.Security.Cryptography.X509Certificates.PublicKey(oid, keyParam, keyValue);
System.Diagnostics.Debug.WriteLine(pubKeyRdr.Key.KeyExchangeAlgorithm);
System.Diagnostics.Debug.WriteLine(pubKeyRdr.Key.KeySize);

It outputs RSA-PKCS1-KeyEx and 1024.

Souse answered 29/6, 2012 at 23:43 Comment(7)
How did you figure this out? What does new byte[]{05, 00} mean?Shipment
05, 00 is the ASN.1 encoding of NULL.Look
The data you provided can be parsed to get the data that was well described by @erickson, to figure out the oid. Like you mentioned, the oid is null originally. Anyway, the null part is mentionedin one of the rfc documents. The way I actually found format is by using X509Certificates.Import() on an existing blah.cer file. I noticed the key param is 0500. As you can see this is not a good explanation for the solution, as to why I didn't post it.Souse
Hopefully someone, possibly erickson will post a clear and concise answer with better reasoning. My question is, why doesn't AsnEncodedData parse the oid from the rawdata? Is it not possible for a general case ASN encoded data?Souse
I tried this code and noticed that pubKeyRdr.Key throws an exception. If I drill down, the parent classes say this is due to an invalid ASN.1.Shipment
Is GetBytes supposed to be Convert.FromBase64String? Does the value I'm converting (30818...) come from a DER parser that isn't in the Framework (or is marked internal?)Shipment
No, it just converts hexadecimal to byte[] array (it's a local function). The value comes from parsing it with a TLV parser, in this case by hand.Souse
L
1

What you have is a SubjectPublicKeyInfo structure. It looks like this:

Sequence {
  Sequence {
    Oid: 1.2.840.113549.1.1.1
    Parameters: null
  }
  KeyValue: blah blah
}

The oid for RSA keys is 1.2.840.113549.1.1.1.

For an RSA key, there are no parameters, so this is null.

However, I don't see any API on AsnEncodedData to parse apart the elements and get at what you need.

Look answered 29/6, 2012 at 22:58 Comment(3)
How did you figure this out? From memory or previous work experience?Shipment
@Shipment I remembered SubjectPublicKeyInfo structure from previous work experience. I determined what you are working with by decoding it here.Look
The parsing logic is in PublicKey's private method DecodePublicKeyObject(). I don't really get why they couldn't have parsed out the ID and param value in the process but it's not too big a deal to do it manually and pass them in if needed.Godinez

© 2022 - 2024 — McMap. All rights reserved.