2 // X509Builder.cs: Abstract builder class for X509 objects
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
8 // (C) 2004 Novell (http://www.novell.com)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
33 using System.Globalization;
34 using System.Security.Cryptography;
38 namespace Mono.Security.X509 {
40 public abstract class X509Builder {
42 private const string defaultHash = "SHA1";
43 private string hashName;
45 protected X509Builder ()
47 hashName = defaultHash;
50 protected abstract ASN1 ToBeSigned (string hashName);
53 protected string GetOid (string hashName)
55 switch (hashName.ToLower (CultureInfo.InvariantCulture)) {
57 // md2withRSAEncryption (1 2 840 113549 1 1 2)
58 return "1.2.840.113549.1.1.2";
60 // md4withRSAEncryption (1 2 840 113549 1 1 3)
61 return "1.2.840.113549.1.1.3";
63 // md5withRSAEncryption (1 2 840 113549 1 1 4)
64 return "1.2.840.113549.1.1.4";
66 // sha1withRSAEncryption (1 2 840 113549 1 1 5)
67 return "1.2.840.113549.1.1.5";
69 // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
70 return "1.2.840.113549.1.1.11";
72 // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
73 return "1.2.840.113549.1.1.12";
75 // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
76 return "1.2.840.113549.1.1.13";
78 throw new NotSupportedException ("Unknown hash algorithm " + hashName);
83 get { return hashName; }
86 hashName = defaultHash;
92 public virtual byte[] Sign (AsymmetricAlgorithm aa)
95 return Sign (aa as RSA);
97 return Sign (aa as DSA);
99 throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString());
102 private byte[] Build (ASN1 tbs, string hashoid, byte[] signature)
104 ASN1 builder = new ASN1 (0x30);
106 builder.Add (PKCS7.AlgorithmIdentifier (hashoid));
107 // first byte of BITSTRING is the number of unused bits in the first byte
108 byte[] bitstring = new byte [signature.Length + 1];
109 Buffer.BlockCopy (signature, 0, bitstring, 1, signature.Length);
110 builder.Add (new ASN1 (0x03, bitstring));
111 return builder.GetBytes ();
114 public virtual byte[] Sign (RSA key)
116 string oid = GetOid (hashName);
117 ASN1 tbs = ToBeSigned (oid);
118 HashAlgorithm ha = HashAlgorithm.Create (hashName);
119 byte[] hash = ha.ComputeHash (tbs.GetBytes ());
121 RSAPKCS1SignatureFormatter pkcs1 = new RSAPKCS1SignatureFormatter (key);
122 pkcs1.SetHashAlgorithm (hashName);
123 byte[] signature = pkcs1.CreateSignature (hash);
125 return Build (tbs, oid, signature);
128 public virtual byte[] Sign (DSA key)
130 string oid = "1.2.840.10040.4.3";
131 ASN1 tbs = ToBeSigned (oid);
132 HashAlgorithm ha = HashAlgorithm.Create (hashName);
134 throw new NotSupportedException ("Only SHA-1 is supported for DSA");
135 byte[] hash = ha.ComputeHash (tbs.GetBytes ());
137 DSASignatureFormatter dsa = new DSASignatureFormatter (key);
138 dsa.SetHashAlgorithm (hashName);
139 byte[] rs = dsa.CreateSignature (hash);
142 byte[] r = new byte [20];
143 Buffer.BlockCopy (rs, 0, r, 0, 20);
144 byte[] s = new byte [20];
145 Buffer.BlockCopy (rs, 20, s, 0, 20);
146 ASN1 signature = new ASN1 (0x30);
147 signature.Add (new ASN1 (0x02, r));
148 signature.Add (new ASN1 (0x02, s));
150 // dsaWithSha1 (1 2 840 10040 4 3)
151 return Build (tbs, oid, signature.GetBytes ());