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