**** Merged from MCS ****
[mono-project.git] / mcs / class / Mono.Security / Mono.Security.X509 / X509CertificateBuilder.cs
blob3ee2816283c20da74de18710da32df5ace0e4a5f
1 //
2 // X509CertificateBuilder.cs: Handles building of X.509 certificates.
3 //
4 // Author:
5 // Sebastien Pouliot <sebastien@ximian.com>
6 //
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8 // (C) 2004 Novell (http://www.novell.com)
9 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System;
33 using System.Security.Cryptography;
35 namespace Mono.Security.X509 {
36 // From RFC3280
38 * Certificate ::= SEQUENCE {
39 * tbsCertificate TBSCertificate,
40 * signatureAlgorithm AlgorithmIdentifier,
41 * signature BIT STRING
42 * }
43 * TBSCertificate ::= SEQUENCE {
44 * version [0] Version DEFAULT v1,
45 * serialNumber CertificateSerialNumber,
46 * signature AlgorithmIdentifier,
47 * issuer Name,
48 * validity Validity,
49 * subject Name,
50 * subjectPublicKeyInfo SubjectPublicKeyInfo,
51 * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
52 * -- If present, version MUST be v2 or v3
53 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
54 * -- If present, version MUST be v2 or v3
55 * extensions [3] Extensions OPTIONAL
56 * -- If present, version MUST be v3 --
57 * }
58 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
59 * CertificateSerialNumber ::= INTEGER
60 * Validity ::= SEQUENCE {
61 * notBefore Time,
62 * notAfter Time
63 * }
64 * Time ::= CHOICE {
65 * utcTime UTCTime,
66 * generalTime GeneralizedTime
67 * }
69 public class X509CertificateBuilder : X509Builder {
71 private byte version;
72 private byte[] sn;
73 private string issuer;
74 private DateTime notBefore;
75 private DateTime notAfter;
76 private string subject;
77 private AsymmetricAlgorithm aa;
78 private byte[] issuerUniqueID;
79 private byte[] subjectUniqueID;
80 private X509ExtensionCollection extensions;
82 public X509CertificateBuilder () : this (3) {}
84 public X509CertificateBuilder (byte version)
86 if (version > 3)
87 throw new ArgumentException ("Invalid certificate version");
88 this.version = version;
89 extensions = new X509ExtensionCollection ();
92 public byte Version {
93 get { return version; }
94 set { version = value; }
97 public byte[] SerialNumber {
98 get { return sn; }
99 set { sn = value; }
102 public string IssuerName {
103 get { return issuer; }
104 set { issuer = value; }
107 public DateTime NotBefore {
108 get { return notBefore; }
109 set { notBefore = value; }
112 public DateTime NotAfter {
113 get { return notAfter; }
114 set { notAfter = value; }
117 public string SubjectName {
118 get { return subject; }
119 set { subject = value; }
122 public AsymmetricAlgorithm SubjectPublicKey {
123 get { return aa; }
124 set { aa = value; }
127 public byte[] IssuerUniqueId {
128 get { return issuerUniqueID; }
129 set { issuerUniqueID = value; }
132 public byte[] SubjectUniqueId {
133 get { return subjectUniqueID; }
134 set { subjectUniqueID = value; }
137 public X509ExtensionCollection Extensions {
138 get { return extensions; }
142 /* SubjectPublicKeyInfo ::= SEQUENCE {
143 * algorithm AlgorithmIdentifier,
144 * subjectPublicKey BIT STRING }
146 private ASN1 SubjectPublicKeyInfo ()
148 ASN1 keyInfo = new ASN1 (0x30);
149 if (aa is RSA) {
150 keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.113549.1.1.1"));
151 RSAParameters p = (aa as RSA).ExportParameters (false);
152 /* RSAPublicKey ::= SEQUENCE {
153 * modulus INTEGER, -- n
154 * publicExponent INTEGER } -- e
156 ASN1 key = new ASN1 (0x30);
157 key.Add (ASN1Convert.FromUnsignedBigInteger (p.Modulus));
158 key.Add (ASN1Convert.FromUnsignedBigInteger (p.Exponent));
159 keyInfo.Add (new ASN1 (UniqueIdentifier (key.GetBytes ())));
161 else if (aa is DSA) {
162 DSAParameters p = (aa as DSA).ExportParameters (false);
163 /* Dss-Parms ::= SEQUENCE {
164 * p INTEGER,
165 * q INTEGER,
166 * g INTEGER }
168 ASN1 param = new ASN1 (0x30);
169 param.Add (ASN1Convert.FromUnsignedBigInteger (p.P));
170 param.Add (ASN1Convert.FromUnsignedBigInteger (p.Q));
171 param.Add (ASN1Convert.FromUnsignedBigInteger (p.G));
172 keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.10040.4.1", param));
173 ASN1 key = keyInfo.Add (new ASN1 (0x03));
174 // DSAPublicKey ::= INTEGER -- public key, y
175 key.Add (ASN1Convert.FromUnsignedBigInteger (p.Y));
177 else
178 throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString ());
179 return keyInfo;
182 private byte[] UniqueIdentifier (byte[] id)
184 // UniqueIdentifier ::= BIT STRING
185 ASN1 uid = new ASN1 (0x03);
186 // first byte in a BITSTRING is the number of unused bits in the first byte
187 byte[] v = new byte [id.Length + 1];
188 Buffer.BlockCopy (id, 0, v, 1, id.Length);
189 uid.Value = v;
190 return uid.GetBytes ();
193 protected override ASN1 ToBeSigned (string oid)
195 // TBSCertificate
196 ASN1 tbsCert = new ASN1 (0x30);
198 if (version > 1) {
199 // TBSCertificate / [0] Version DEFAULT v1,
200 byte[] ver = { (byte)(version - 1) };
201 ASN1 v = tbsCert.Add (new ASN1 (0xA0));
202 v.Add (new ASN1 (0x02, ver));
205 // TBSCertificate / CertificateSerialNumber,
206 tbsCert.Add (new ASN1 (0x02, sn));
208 // TBSCertificate / AlgorithmIdentifier,
209 tbsCert.Add (PKCS7.AlgorithmIdentifier (oid));
211 // TBSCertificate / Name
212 tbsCert.Add (X501.FromString (issuer));
214 // TBSCertificate / Validity
215 ASN1 validity = tbsCert.Add (new ASN1 (0x30));
216 // TBSCertificate / Validity / Time
217 validity.Add (ASN1Convert.FromDateTime (notBefore));
218 // TBSCertificate / Validity / Time
219 validity.Add (ASN1Convert.FromDateTime (notAfter));
221 // TBSCertificate / Name
222 tbsCert.Add (X501.FromString (subject));
224 // TBSCertificate / SubjectPublicKeyInfo
225 tbsCert.Add (SubjectPublicKeyInfo ());
227 if (version > 1) {
228 // TBSCertificate / [1] IMPLICIT UniqueIdentifier OPTIONAL
229 if (issuerUniqueID != null)
230 tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (issuerUniqueID)));
232 // TBSCertificate / [2] IMPLICIT UniqueIdentifier OPTIONAL
233 if (subjectUniqueID != null)
234 tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (subjectUniqueID)));
236 // TBSCertificate / [3] Extensions OPTIONAL
237 if ((version > 2) && (extensions.Count > 0))
238 tbsCert.Add (new ASN1 (0xA3, extensions.GetBytes ()));
241 return tbsCert;