Toon posts:

[C# + CAPICOM] capicom + Web Client Certificate

Pagina: 1
Acties:
  • 306 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Goeiemiddag,

ik ben al een dag bezig om met capicom een web certificaat uit te lezen, maar ergens wringt er nog wat. Hieronder mijn functie:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
( Certificate is de property Certificate van de HttpClientCertificate klasse, is gewoon gevuld)
public static string GetSubjectAlternativeName(byte[] Certificate)
{
    string sSubAltName = "";
    // hieronder staan de drie mogelijkheden die ik geprobeerd heb, alleen geven zelfde fout en probeer er natuurlijk maar 1 tegelijk
    CAPICOM.Certificate CCC = new CertificateClass();
    CAPICOM.CertificateClass CCC = new CertificateClass();
    CAPICOM.ICertificate iCC = new CertificateClass();

    CAPICOM.Utilities CUT = new UtilitiesClass();
    string sByteString = CUT.ByteArrayToBinaryString(Certificate);

    //de functies hieronder geven aan dat de class niet is geinitialiseerd, maar kan ook zijn omdat er nog niets instaat, dat hij daarom die fout geeft
    //bool bBool = CCC.Archived;
    //CCC.Display();

               //HIERONDER de echte regels waar het om draait. Elke van deze regels geeft een foutmelding
    iCC.Import(sByteString);
    CCC.Import(sByteString);
    CCC.ICertificate_Import(sByteString);

    foreach(Extension Extension in CCC.Extensions())
    {
    if (Extension.OID.FriendlyName == "Subject Alternative Name")
        {
        sSubAltName = Extension.EncodedData.Format(true);break;
        }
    }
    return sSubAltName;
}


En hier de foutmelding:
Cannot find the requested object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Runtime.InteropServices.COMException: Cannot find the requested object.

Source Error:


Line 24: //bool bBool = CCC.Archived;
Line 25: //CCC.Display();
Line 26: iCC.Import(sByteString);
Line 27: CCC.ICertificate_Import(sByteString);
Line 28: //string sIssuer = CCC.ICertificate_IssuerName;


Source File: d:\projects\dotnet\contentgenie\cg2.capicom\capicom.cs Line: 26

Stack Trace:


[COMException (0x80092009): Cannot find the requested object.]
CAPICOM.CertificateClass.ICertificate_Import(String EncodedCertificate) +0
--- rest van stacktrace niet belangrijk ---


Wat is the missing link.

tia,

Youri

  • dotcode
  • Registratie: Augustus 2003
  • Laatst online: 14-08 11:19

dotcode

///\00/\\

Hierbij wat hulp, was effe zoek :):

Je moet een BSTR make in managed code.


Kijk naar de MyCertificateImport() methode. Deze laat zien hoe je dat doet BSTR in managed code.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
using System; 
using System.Reflection; 
using System.Runtime.InteropServices; 
using capicomrcw; 
namespace RCWInteropWorkAround 
{ 
/// <summary> 
/// Summary description for Class1. 
/// </summary> 
class Class1 
{ 
/// <summary> 
/// The main entry point for the application. 
/// </summary> 
[STAThread] 
static void Main(string[] args) 
{ 
try 
{ 
string password = ""; 
int argc = args.GetLength(0); 
// Check command line arguments. 
if (1 > argc || 2 < argc) 
{ 
throw new ArgumentException(); 
} 
// Get password if provided. 
if (2 == argc) 
{ 
password = args[1]; 
} 
// Load certificate from file. 
CertificateClass certificate = new CertificateClass(); 
certificate.Load(args[0], password, 
CAPICOM_KEY_STORAGE_FLAG.CAPICOM_KEY_STORAGE_DEFAULT, 
CAPICOM_KEY_LOCATION.CAPICOM_CURRENT_USER_KEY); 
// Import the certificate file, and return the blob as byte array. 
byte[] byteCert = MyCertificateExport(certificate); 
// Import the certificate from a byte array. 
certificate = MyCertificateImport(byteCert); 


// Now display the cert, so that we know it works! 
certificate.Display(); 
} 
catch (ArgumentException) 
{ 
Console.WriteLine("Usage: {0} FileName [Password].", 
Assembly.GetExecutingAssembly().GetModules()[0]); 
} 
catch (Exception e) 
{ 
Console.WriteLine(e.Message); 
} 
} 
///////////////////////////////////////////////////////////////////////// 
/// 
/// <summary> 
/// Export the certificate as byte array. 
/// 
/// Note: In order for this to work, you must creat a custom COM interop 
CertificateClass. 
/// For example: 
/// 
/// 1. tlbimp capicom.dll /out:capicomrcw.dll 
/// 2. ildasm /out:capicomrcw.il capicomrcw.dll 
/// 3. edit capicomrcw.il using your favorite text editor 
/// a. find all occurences of Certificate::Export method in the class 
/// and interface sections (should have 4). 
/// b. replace the line "instance string" with "instance native int" 
/// c. delete the line "marshal( bstr )" 
/// 4. Save the changes 
/// 5. del capicomrcw.dll 
/// 6. ilasm /dll capicomrcw.il /res:capicomrcw. 
/// </summary> 
/// <param name="certificate"></param> 
/// <returns></returns> 
/// 
static byte[] MyCertificateExport(CertificateClass certificate) 
{ 
// Export it as fixed pointer to the BSTR originally created by CAPICOM. 
IntPtr bstrCert = 
certificate.Export(CAPICOM_ENCODING_TYPE.CAPICOM_ENCODE_BINARY); 
// Now find the length of the BSTR. 
Int32 bstrLength = Marshal.ReadInt32(bstrCert, -4); 
Byte[] byteCert = new Byte[bstrLength]; 
#if DEBUG 
// Output debug info. 
Console.WriteLine("Certificate Length = {0}", byteCert.Length); 
#endif 
// Copy the content of the BSTR to the byte array. 
Marshal.Copy(bstrCert, byteCert, 0, bstrLength); 
// Remember, we MUST free the BSTR ourselves. 
Marshal.FreeBSTR(bstrCert); 
return byteCert; 
} 
///////////////////////////////////////////////////////////////////////// 
/// 
/// <summary> 
/// Import the byte array and return it as a certificate object. 
/// 
/// Note: In order for this to work, you must creat a custom COM interop 
CertificateClass. 
/// For example: 
/// 
/// 1. Follow the steps outlined above in the export method. 
/// 2. edit capicomrcw.il using your favorite text editor 
/// a. find all occurences of Certificate::Import method in the class 
/// and interface sections (should have 4). 
/// b. replace the parameter "[in] string marshal( bstr)" with "[in] native 
int" 
/// 3. Save the changes 
/// 4. del capicomrcw.dll 
/// 5. ilasm /dll capicomrcw.il /res:capicomrcw. 
/// </summary> 
/// <param name="byteCert"></param> 
/// <returns></returns> 
static CertificateClass MyCertificateImport(byte[] byteCert) 
{ 
// Instantiate a certificate object. 
CertificateClass certificate = new CertificateClass(); 
// Now we need to hand construct a BSTR ourselves. 
// 1. Bump up to even if odd. 
// 2. Add 4 bytes for length. 
// 3. Add two bytes for the terminating NULL character. 
byte[] bstr = new byte[((byteCert.Length + 1) & 0xfffe) + 6]; 
#if DEBUG 
// Output debug info. 
Console.WriteLine("BSTR Length = {0}", bstr.Length); 
#endif 
// We can only do this in unsafe mode. 
unsafe 
{ 
fixed(byte * pbstr = bstr) 
{ 
int * pInt = (int *) pbstr; 
// Set the BSTR length. 
*pInt = byteCert.Length; 
// Copy the BSTR content. 
Buffer.BlockCopy(byteCert, 0, bstr, 4, byteCert.Length); 
// Point pass the length. 
fixed(byte * bstrPtr = &bstr[4]) 
{ 
// Now import it! 
certificate.Import(new IntPtr(bstrPtr)); 
} 
} 
} 
return certificate; 
} 
} 
}


Peter
This posting is provided "AS IS" with no warranties, and confers no rights.