@@ -2,179 +2,25 @@ namespace Docker.DotNet.X509;
22
33public static class RSAUtil
44{
5- private const byte Padding = 0x00 ;
6-
75 public static X509Certificate2 GetCertFromPFX ( string pfxFilePath , string password )
86 {
7+ #if NET9_0_OR_GREATER
8+ return X509CertificateLoader . LoadPkcs12FromFile ( pfxFilePath , password ) ;
9+ #else
910 return new X509Certificate2 ( pfxFilePath , password ) ;
11+ #endif
1012 }
1113
12- public static X509Certificate2 GetCertFromPFXSecure ( string pfxFilePath , SecureString password )
13- {
14- return new X509Certificate2 ( pfxFilePath , password ) ;
15- }
16-
17- public static X509Certificate2 GetCertFromPEMFiles ( string certFilePath , string keyFilePath )
18- {
19- var cert = new X509Certificate2 ( certFilePath ) ;
20- cert . PrivateKey = ReadFromPemFile ( keyFilePath ) ;
21- return cert ;
22- }
23-
24- private static RSACryptoServiceProvider ReadFromPemFile ( string pemFilePath )
25- {
26- var allBytes = File . ReadAllBytes ( pemFilePath ) ;
27- var mem = new MemoryStream ( allBytes ) ;
28- var startIndex = 0 ;
29- var endIndex = 0 ;
30-
31- using ( var rdr = new BinaryReader ( mem ) )
32- {
33- if ( ! TryReadUntil ( rdr , "-----BEGIN RSA PRIVATE KEY-----" ) )
34- {
35- throw new Exception ( "Invalid file format expected. No begin tag." ) ;
36- }
37-
38- startIndex = ( int ) ( mem . Position ) ;
39-
40- const string endTag = "-----END RSA PRIVATE KEY-----" ;
41- if ( ! TryReadUntil ( rdr , endTag ) )
42- {
43- throw new Exception ( "Invalid file format expected. No end tag." ) ;
44- }
45-
46- endIndex = ( int ) ( mem . Position - endTag . Length - 2 ) ;
47- }
48-
49- // Convert the bytes from base64;
50- var convertedBytes = Convert . FromBase64String ( Encoding . UTF8 . GetString ( allBytes , startIndex , endIndex - startIndex ) ) ;
51- mem = new MemoryStream ( convertedBytes ) ;
52- using ( var rdr = new BinaryReader ( mem ) )
53- {
54- var val = rdr . ReadUInt16 ( ) ;
55- if ( val != 0x8230 )
56- {
57- throw new Exception ( "Invalid byte ordering." ) ;
58- }
59-
60- // Discard the next bits of the version.
61- rdr . ReadUInt32 ( ) ;
62- if ( rdr . ReadByte ( ) != Padding )
63- {
64- throw new InvalidDataException ( "Invalid ASN.1 format." ) ;
65- }
66-
67- var rsa = new RSAParameters ( )
68- {
69- Modulus = rdr . ReadBytes ( ReadIntegerCount ( rdr ) ) ,
70- Exponent = rdr . ReadBytes ( ReadIntegerCount ( rdr ) ) ,
71- D = rdr . ReadBytes ( ReadIntegerCount ( rdr ) ) ,
72- P = rdr . ReadBytes ( ReadIntegerCount ( rdr ) ) ,
73- Q = rdr . ReadBytes ( ReadIntegerCount ( rdr ) ) ,
74- DP = rdr . ReadBytes ( ReadIntegerCount ( rdr ) ) ,
75- DQ = rdr . ReadBytes ( ReadIntegerCount ( rdr ) ) ,
76- InverseQ = rdr . ReadBytes ( ReadIntegerCount ( rdr ) )
77- } ;
78-
79- // Use "1" to indicate RSA.
80- var csp = new CspParameters ( 1 )
81- {
82-
83- // Set the KeyContainerName so that native code that looks up the private key
84- // can find it. This produces a keyset file on disk as a side effect.
85- KeyContainerName = pemFilePath
86- } ;
87- var rsaProvider = new RSACryptoServiceProvider ( csp )
88- {
89-
90- // Setting to false makes sure the keystore file will be cleaned up
91- // when the current process exits.
92- PersistKeyInCsp = false
93- } ;
94-
95- // Import the private key into the keyset.
96- rsaProvider . ImportParameters ( rsa ) ;
97-
98- return rsaProvider ;
99- }
100- }
101-
102- /// <summary>
103- /// Reads an integer count encoding in DER ASN.1 format.
104- /// <summary>
105- private static int ReadIntegerCount ( BinaryReader rdr )
14+ public static X509Certificate2 GetCertFromPEM ( string certFilePath , string keyFilePath )
10615 {
107- const byte highBitOctet = 0x80 ;
108- const byte ASN1_INTEGER = 0x02 ;
109-
110- if ( rdr . ReadByte ( ) != ASN1_INTEGER )
111- {
112- throw new Exception ( "Integer tag expected." ) ;
113- }
114-
115- int count = 0 ;
116- var val = rdr . ReadByte ( ) ;
117- if ( ( val & highBitOctet ) == highBitOctet )
118- {
119- byte numOfOctets = ( byte ) ( val - highBitOctet ) ;
120- if ( numOfOctets > 4 )
121- {
122- throw new InvalidDataException ( "Too many octets." ) ;
123- }
124-
125- for ( var i = 0 ; i < numOfOctets ; i ++ )
126- {
127- count <<= 8 ;
128- count += rdr . ReadByte ( ) ;
129- }
130- }
131- else
132- {
133- count = val ;
134- }
135-
136- while ( rdr . ReadByte ( ) == Padding )
137- {
138- count -- ;
139- }
140-
141- // The last read was a valid byte. Go back here.
142- rdr . BaseStream . Seek ( - 1 , SeekOrigin . Current ) ;
143-
144- return count ;
145- }
146-
147- /// <summary>
148- /// Reads until the matching PEM tag is found.
149- /// <summary>
150- private static bool TryReadUntil ( BinaryReader rdr , string tag )
151- {
152- char delim = '\n ' ;
153- char c ;
154- char [ ] line = new char [ 64 ] ;
155- int index ;
156-
157- try
158- {
159- do
160- {
161- index = 0 ;
162- while ( ( c = rdr . ReadChar ( ) ) != delim )
163- {
164- if ( c == '\r ' )
165- {
166- continue ;
167- }
168- line [ index ] = c ;
169- index ++ ;
170- }
171- } while ( new string ( line , 0 , index ) != tag ) ;
172-
173- return true ;
174- }
175- catch ( EndOfStreamException )
176- {
177- return false ;
178- }
16+ #if NETSTANDARD
17+ return Polyfills . X509Certificate2 . CreateFromPemFile ( certFilePath , keyFilePath ) ;
18+ #elif NET9_0_OR_GREATER
19+ var certificate = X509Certificate2 . CreateFromPemFile ( certFilePath , keyFilePath ) ;
20+ return OperatingSystem . IsWindows ( ) ? X509CertificateLoader . LoadPkcs12 ( certificate . Export ( X509ContentType . Pfx ) , null ) : certificate ;
21+ #elif NET6_0_OR_GREATER
22+ var certificate = X509Certificate2 . CreateFromPemFile ( certFilePath , keyFilePath ) ;
23+ return OperatingSystem . IsWindows ( ) ? new X509Certificate2 ( certificate . Export ( X509ContentType . Pfx ) ) : certificate ;
24+ #endif
17925 }
18026}
0 commit comments