简体   繁体   中英

RSA modulus and exponent from public key

I basically have the same problem as in this question , but I'm having trouble filling in the apparently trivial parts left out from the accepted answer. I'm doing this in C# with Mono.

I have a CA root certificate, and from that I can get a byte[] holding a public key. I then get an untrusted certificate I need to verify. From what I understand, RSACryptoServiceProvider.VerifyData should do the trick, but first I need to set RSAParameters with the modulus and exponent from the public key.

(Edit: The following repeats some things already apparent from the question I linked to above.)
The piece of code that should do what I need and validate a server's certificate with a root certificate I trust is as follows:

RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider();
RSAParameters publicKeyParams = new RSAParameters();
publicKeyParams.Modulus = GetPublicKeyModulus();
publicKeyParams.Exponent = GetPublicKeyExponent();
publicKey.ImportParameters(publicKeyParams);
return publicKey.VerifyData(SignedValue(), CryptoConfig.MapNameToOID("SHA1"), Signature());

My problem is the contents of the GetPublicKeyModulus() and GetPublicKeyExponent(). In the accepted answer they are left out as apparently trivial, with just a comment saying the modulus is the value of the first TLV in my public key, and the exponent is the second TLV in the public key. I don't fully understand what that means.

byte[] GetPublicKeyExponent()
{
  // The value of the second TLV in your Public Key
}

byte[] GetPublicKeyModulus()
{
  // The value of the first TLV in your Public Key
}
byte[] SignedValue()
{
  // The first TLV in your Ceritificate
}

byte[] Signature()
{
  // The value of the third TLV in your Certificate
}

My question is what do these "first TLV"/"second TLV" exactly mean and how do I get those values from the byte array I have?

From what I understand, TLV stands for type-length-value. So if I have it correct, first bits of the byte array containing the public key have information about how many bits the modulus data is. Using that information I'm supposed to copy that amount of bits from the public key into another array, and set RSAParameters.Modulus to that value. After the modulus in the public key comes the exponent, and I should do the same operation with that. But I can't find information about in how many bits and in what format is the "TL" part of a TLV in the public key data contained.

I found information elsewhere saying the modulus is the first 1024 bits in the public key, and the exponent is the remainder, but that gave me an error about size when copying data between the byte arrays.

At the moment my code that I've been forming based on the accepted answer in the question I linked looks basically like this:

using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;

X509Certificate2 trustedRootCertificate = new X509Certificate2(X509Certificate2.CreateFromCertFile(filename));
ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate;
.
.
public bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
  .
  .
  byte[] publicKeyBytes = trustedRootCertificate.GetPublicKey();
  byte[] modulusData = // The value of the first TLV in the Public Key??
  byte[] exponentData = // The value of the second TLV in the Public Key??

  RSAParameters publicKeyParams = new RSAParameters();
  publicKeyParams.Modulus = modulusData;
  publicKeyParams.Exponent = exponentData;
  RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider();
  publicKey.ImportParameters(publicKeyParams);

  byte[] certificateData = certificate.GetRawCertData();
  byte[] signedValue = // The first TLV in the certificate??
  byte[] encryptedSignature = // The third TLV in the certificate??

  return publicKey.VerifyData(certificateData, HashAlgorithm.Create("SHA1"), encryptedSignature);
}

Or should I be using certificateData (the return value of certificate.GetRawCertData()) in the VerifyData call?

Elsewhere I've found that the encrypted signature part is the last 256 bits in the certificateData, I'm not sure if that's the same as "the third TLV in the certificate". If not, I'd be doing

byte[] certificateData = certificate.GetRawCertData();
byte[] encryptedSignature = new byte[256];
System.Array.Copy(certificateData, certificateData.Length - 256, encryptedSignature, 0, 256);

and then using encryptedSignature as the last parameter in the VerifyData call.

Instead of all this TLV business I've also tried simply

RSACryptoServiceProvider publicKey = trustedRootCertificate.PublicKey.Key as RSACryptoServiceProvider;

as the person in the question I linked to above, but using this the VerifyData call then returned false when I thought it shouldn't. The certificate the application gets from the server has trustedRootCertificate as its root cert, I should be able to do this with that, correct? The root's public key should be able to verify the server's cert?

It's very much possible I just have the very basics of certificate verification wrong from the start. If that's not the case, then my question is how do I get these values

// The value of the second TLV in your Public Key
..
// The value of the first TLV in your Public Key

from the public key of the trusted root cert I have.

Edit: I've also verified that the root certificate loaded from the file and the certificate the app gets from the server are what they're supposed to be by printing out their information, so the problem is not at least in the certificates being wrong. I just don't know how to use them correctly.

Lets say that you encountered with BIT STRING type containing the following Length - Value::

03(T - BIT STRING) 
82(Read next 2 Bytes for actual Length) 
01 0F(Actual Length of whole BIT STRING) 

---BIT STRING Value Starts Here---
00(First Byte Of BIT STRING specifies the number of bits left unused in the final byte of BIT STRING which in this case is 0)

30(T - SEQUENCE) 
82(Read next 2 Bytes for actual Length) 
01 0A(Actual Length of whole SEQUENCE) 

---SEQUENCE Value Starts Here---
02(T - INTEGER) 
82(Read next 2 Bytes for actual Length) 
01 01(Actual Length of whole INTEGER) 

(Value starts from here till "Actual Length of whole INTEGER above")
---INTEGER Value Starts Here---
---Exponent Starts Here---
00 A9  CA B2 A4 CC CD 20 AF 0A
7D 89 AC 87 75 F0 B4 4E  F1 DF C1 0F BF 67 61 BD
A3 64 1C DA BB F9 CA 33  AB 84 30 89 58 7E 8C DB
6B DD 36 9E 0F BF D1 EC  78 F2 77 A6 7E 6F 3C BF
93 AF 0D BA 68 F4 6C 94  CA BD 52 2D AB 48 3D F5
B6 D5 5D 5F 1B 02 9F FA  2F 6B 1E A4 F7 A3 9A A6
1A C8 02 E1 7F 4C 52 E3  0E 60 EC 40 1C 7E B9 0D
DE 3F C7 B4 DF 87 BD 5F  7A 6A 31 2E 03 99 81 13
A8 47 20 CE 31 73 0D 57  2D CD 78 34 33 95 12 99
12 B9 DE 68 2F AA E6 E3  C2 8A 8C 2A C3 8B 21 87
66 BD 83 58 57 6F 75 BF  3C AA 26 87 5D CA 10 15
3C 9F 84 EA 54 C1 0A 6E  C4 FE C5 4A DD B9 07 11
97 22 7C DB 3E 27 D1 1E  78 EC 9F 31 C9 F1 E6 22
19 DB C4 B3 47 43 9A 1A  5F A0 1E 90 E4 5E F5 EE
7C F1 7D AB 62 01 8F F5  4D 0B DE D0 22 56 A8 95
CD AE 88 76 AE EE BA 0D  F3 E4 4D D9 A0 FB 68 A0
AE 14 3B B3 87 C1 BB 
-----Exponent Ends Here----
---INTEGER Value Ends Here---


02(T - INTEGER)  
03(Actual Length cuz 8th Bit Not Set here, so this byte shows the actual length)

---INTEGER Value Starts Here---
----Mod Starts Here--- 
01 00 01
---Mod Ends Here---
---INTEGER Value Ends Here---

---SEQUENCE Value Ends Here---
---BIT STRING Value Ends Here---

You might want to read ASN.1 Format

With RSACryptoServiceProvider:

X509Certificate2 certificate = Certificate.CreateFromBase64String(stringCert);
RSACryptoServiceProvider key = certificate.PublicKey.Key as RSACryptoServiceProvider;
if(key != null)
{
    RSAParameters parameters = key.ExportParameters(false);
    byte[] expoenet = parameters.Exponent;
    byte[] modulus = parameters.Modulus;
} 

https://social.msdn.microsoft.com/Forums/vstudio/en-US/4282dda1-4803-435a-b63a-65e2d5ac9941/get-modulus-exponent-from-certificate-public-key?forum.netfxbcl

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM