[corlib] New lazily initialized X509Certificate.
[mono.git] / mcs / class / corlib / System.Security.Cryptography.X509Certificates / X509CertificateImplApple.cs
1 using System;
2 using System.Text;
3 using System.Runtime.InteropServices;
4 using XamMac.CoreFoundation;
5 using MX = Mono.Security.X509;
6
7 namespace System.Security.Cryptography.X509Certificates
8 {
9         class X509CertificateImplApple : X509CertificateImpl
10         {
11                 IntPtr handle;
12                 X509CertificateImpl fallback;
13
14                 public X509CertificateImplApple (IntPtr handle, bool owns)
15                 {
16                         this.handle = handle;
17                         if (!owns)
18                                 CFHelpers.CFRetain (handle);
19                 }
20
21                 public override bool IsValid {
22                         get { return handle != IntPtr.Zero; }
23                 }
24
25                 public override IntPtr Handle {
26                         get { return handle; }
27                 }
28
29                 public override X509CertificateImpl Clone ()
30                 {
31                         ThrowIfContextInvalid ();
32                         return new X509CertificateImplApple (handle, false);
33                 }
34
35                 [DllImport (CFHelpers.SecurityLibrary)]
36                 extern static IntPtr SecCertificateCopySubjectSummary (IntPtr cert);
37
38                 [DllImport (CFHelpers.SecurityLibrary)]
39                 extern static IntPtr SecCertificateCopyData (IntPtr cert);
40
41                 public override byte[] GetRawCertData ()
42                 {
43                         ThrowIfContextInvalid ();
44                         var data = SecCertificateCopyData (handle);
45                         if (data == IntPtr.Zero)
46                                 throw new ArgumentException ("Not a valid certificate");
47
48                         try {
49                                 return CFHelpers.FetchDataBuffer (data);
50                         } finally {
51                                 CFHelpers.CFRelease (data);
52                         }
53                 }
54
55                 public override string GetSubjectSummary ()
56                 {
57                         ThrowIfContextInvalid ();
58                         IntPtr cfstr = SecCertificateCopySubjectSummary (handle);
59                         string ret = CFHelpers.FetchString (cfstr);
60                         CFHelpers.CFRelease (cfstr);
61                         return ret;
62                 }
63
64                 protected override byte[] GetCertHash (bool lazy)
65                 {
66                         // FIXME: might just return 'null' when 'lazy' is true.
67                         ThrowIfContextInvalid ();
68                         SHA1 sha = SHA1.Create ();
69                         return sha.ComputeHash (GetRawCertData ());
70                 }
71
72                 public override bool Equals (X509CertificateImpl other, out bool result)
73                 {
74                         var otherAppleImpl = other as X509CertificateImplApple;
75                         if (otherAppleImpl != null && otherAppleImpl.handle == handle) {
76                                 result = true;
77                                 return true;
78                         }
79
80                         result = false;
81                         return false;
82                 }
83
84                 void MustFallback ()
85                 {
86                         ThrowIfContextInvalid ();
87                         if (fallback != null)
88                                 return;
89                         var mxCert = new MX.X509Certificate (GetRawCertData ());
90                         fallback = new X509CertificateImplMono (mxCert);
91                 }
92
93                 public X509CertificateImpl FallbackImpl {
94                         get {
95                                 MustFallback ();
96                                 return fallback;
97                         }
98                 }
99
100                 public override string GetSubjectName (bool legacyV1Mode)
101                 {
102                         return FallbackImpl.GetSubjectName (legacyV1Mode);
103                 }
104
105                 public override string GetIssuerName (bool legacyV1Mode)
106                 {
107                         return FallbackImpl.GetIssuerName (legacyV1Mode);
108                 }
109
110                 public override DateTime GetEffectiveDateString ()
111                 {
112                         return FallbackImpl.GetEffectiveDateString ();
113                 }
114
115                 public override DateTime GetExpirationDateString ()
116                 {
117                         return FallbackImpl.GetExpirationDateString ();
118                 }
119
120                 public override string GetKeyAlgorithm ()
121                 {
122                         return FallbackImpl.GetKeyAlgorithm ();
123                 }
124
125                 public override byte[] GetKeyAlgorithmParameters ()
126                 {
127                         return FallbackImpl.GetKeyAlgorithmParameters ();
128                 }
129
130                 public override byte[] GetPublicKey ()
131                 {
132                         return FallbackImpl.GetPublicKey ();
133                 }
134
135                 public override byte[] GetSerialNumber ()
136                 {
137                         return FallbackImpl.GetSerialNumber ();
138                 }
139
140                 public override byte[] Export (X509ContentType contentType, byte[] password)
141                 {
142                         ThrowIfContextInvalid ();
143
144                         switch (contentType) {
145                         case X509ContentType.Cert:
146                                 return GetRawCertData ();
147                         case X509ContentType.Pfx: // this includes Pkcs12
148                                 // TODO
149                                 throw new NotSupportedException ();
150                         case X509ContentType.SerializedCert:
151                                 // TODO
152                                 throw new NotSupportedException ();
153                         default:
154                                 string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
155                                 throw new CryptographicException (msg);
156                         }
157                 }
158
159                 public override string ToString (bool full)
160                 {
161                         ThrowIfContextInvalid ();
162
163                         if (!full || fallback == null) {
164                                 var summary = GetSubjectSummary ();
165                                 return string.Format ("[X509Certificate: {0}]", summary);
166                         }
167
168                         string nl = Environment.NewLine;
169                         StringBuilder sb = new StringBuilder ();
170                         sb.AppendFormat ("[Subject]{0}  {1}{0}{0}", nl, GetSubjectName (false));
171
172                         sb.AppendFormat ("[Issuer]{0}  {1}{0}{0}", nl, GetIssuerName (false));
173                         sb.AppendFormat ("[Not Before]{0}  {1}{0}{0}", nl, GetEffectiveDateString ());
174                         sb.AppendFormat ("[Not After]{0}  {1}{0}{0}", nl, GetExpirationDateString ());
175                         sb.AppendFormat ("[Thumbprint]{0}  {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
176
177                         sb.Append (nl);
178                         return sb.ToString ();
179                 }
180
181                 protected override void Dispose (bool disposing)
182                 {
183                         if (handle != IntPtr.Zero){
184                                 CFHelpers.CFRelease (handle);
185                                 handle = IntPtr.Zero;
186                         }
187                         if (fallback != null) {
188                                 fallback.Dispose ();
189                                 fallback = null;
190                         }
191                 }
192         }
193 }