Xamarin Public Jenkins (auto-signing) 64ac736ec5 Imported Upstream version 6.0.0.172
Former-commit-id: f3cc9b82f3e5bd8f0fd3ebc098f789556b44e9cd
2019-04-12 14:10:50 +00:00

633 lines
16 KiB
C#

//
// System.Security.Cryptography.X509Certificate2 class
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#if MONO_SECURITY_ALIAS
extern alias MonoSecurity;
using MonoSecurity::Mono.Security;
using MonoSecurity::Mono.Security.Cryptography;
using MX = MonoSecurity::Mono.Security.X509;
#else
using Mono.Security;
using Mono.Security.Cryptography;
using MX = Mono.Security.X509;
#endif
using System.IO;
using System.Text;
using System.Collections;
using System.Runtime.Serialization;
using Microsoft.Win32.SafeHandles;
using Internal.Cryptography;
using Mono;
namespace System.Security.Cryptography.X509Certificates
{
[Serializable]
public class X509Certificate2 : X509Certificate
{
volatile byte[] lazyRawData;
volatile Oid lazySignatureAlgorithm;
volatile int lazyVersion;
volatile X500DistinguishedName lazySubjectName;
volatile X500DistinguishedName lazyIssuerName;
volatile PublicKey lazyPublicKey;
volatile AsymmetricAlgorithm lazyPrivateKey;
volatile X509ExtensionCollection lazyExtensions;
public override void Reset ()
{
lazyRawData = null;
lazySignatureAlgorithm = null;
lazyVersion = 0;
lazySubjectName = null;
lazyIssuerName = null;
lazyPublicKey = null;
lazyPrivateKey = null;
lazyExtensions = null;
base.Reset ();
}
public X509Certificate2 ()
: base ()
{
}
public X509Certificate2 (byte[] rawData)
: base (rawData)
{
// MONO: temporary hack until `X509CertificateImplApple` derives from
// `X509Certificate2Impl`.
if (rawData != null && rawData.Length != 0) {
using (var safePasswordHandle = new SafePasswordHandle ((string)null)) {
var impl = X509Helper.Import (rawData, safePasswordHandle, X509KeyStorageFlags.DefaultKeySet);
ImportHandle (impl);
}
}
}
public X509Certificate2 (byte[] rawData, string password)
: base (rawData, password)
{
}
[CLSCompliantAttribute (false)]
public X509Certificate2 (byte[] rawData, SecureString password)
: base (rawData, password)
{
}
public X509Certificate2 (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
: base (rawData, password, keyStorageFlags)
{
}
[CLSCompliantAttribute (false)]
public X509Certificate2 (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags)
: base (rawData, password, keyStorageFlags)
{
}
public X509Certificate2 (IntPtr handle)
: base (handle)
{
}
internal X509Certificate2 (X509Certificate2Impl impl)
: base (impl)
{
}
public X509Certificate2 (string fileName)
: base (fileName)
{
}
public X509Certificate2 (string fileName, string password)
: base (fileName, password)
{
}
public X509Certificate2 (string fileName, SecureString password)
: base (fileName, password)
{
}
public X509Certificate2 (string fileName, string password, X509KeyStorageFlags keyStorageFlags)
: base (fileName, password, keyStorageFlags)
{
}
public X509Certificate2 (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags)
: base (fileName, password, keyStorageFlags)
{
}
public X509Certificate2 (X509Certificate certificate)
: base (certificate)
{
}
protected X509Certificate2 (SerializationInfo info, StreamingContext context)
: base (info, context)
{
throw new PlatformNotSupportedException ();
}
public bool Archived {
get {
ThrowIfInvalid ();
return Impl.Archived;
}
set {
ThrowIfInvalid ();
Impl.Archived = value;
}
}
public X509ExtensionCollection Extensions {
get {
ThrowIfInvalid ();
X509ExtensionCollection extensions = lazyExtensions;
if (extensions == null) {
extensions = new X509ExtensionCollection ();
foreach (X509Extension extension in Impl.Extensions) {
X509Extension customExtension = CreateCustomExtensionIfAny (extension.Oid);
if (customExtension == null) {
extensions.Add (extension);
} else {
customExtension.CopyFrom (extension);
extensions.Add (customExtension);
}
}
lazyExtensions = extensions;
}
return extensions;
}
}
public string FriendlyName {
get {
ThrowIfInvalid ();
return Impl.FriendlyName;
}
set {
ThrowIfInvalid ();
Impl.FriendlyName = value;
}
}
public bool HasPrivateKey {
get {
ThrowIfInvalid ();
return Impl.HasPrivateKey;
}
}
public AsymmetricAlgorithm PrivateKey {
get {
ThrowIfInvalid ();
if (!HasPrivateKey)
return null;
if (lazyPrivateKey == null) {
switch (GetKeyAlgorithm ()) {
case Oids.RsaRsa:
lazyPrivateKey = Impl.GetRSAPrivateKey ();
break;
case Oids.DsaDsa:
lazyPrivateKey = Impl.GetDSAPrivateKey ();
break;
default:
// This includes ECDSA, because an Oids.Ecc key can be
// many different algorithm kinds, not necessarily with mutual exclusion.
//
// Plus, .NET Framework only supports RSA and DSA in this property.
throw new NotSupportedException (SR.NotSupported_KeyAlgorithm);
}
}
return lazyPrivateKey;
}
set {
throw new PlatformNotSupportedException ();
}
}
public X500DistinguishedName IssuerName {
get {
ThrowIfInvalid ();
X500DistinguishedName issuerName = lazyIssuerName;
if (issuerName == null)
issuerName = lazyIssuerName = Impl.IssuerName;
return issuerName;
}
}
public DateTime NotAfter {
get { return GetNotAfter (); }
}
public DateTime NotBefore {
get { return GetNotBefore (); }
}
public PublicKey PublicKey {
get {
ThrowIfInvalid ();
PublicKey publicKey = lazyPublicKey;
if (publicKey == null) {
string keyAlgorithmOid = GetKeyAlgorithm ();
byte[] parameters = GetKeyAlgorithmParameters ();
byte[] keyValue = GetPublicKey ();
Oid oid = new Oid (keyAlgorithmOid);
publicKey = lazyPublicKey = new PublicKey (oid, new AsnEncodedData (oid, parameters), new AsnEncodedData (oid, keyValue));
}
return publicKey;
}
}
public byte[] RawData {
get {
ThrowIfInvalid ();
byte[] rawData = lazyRawData;
if (rawData == null)
rawData = lazyRawData = Impl.RawData;
return rawData.CloneByteArray ();
}
}
public string SerialNumber {
get {
return GetSerialNumberString ();
}
}
public Oid SignatureAlgorithm {
get {
ThrowIfInvalid ();
Oid signatureAlgorithm = lazySignatureAlgorithm;
if (signatureAlgorithm == null) {
string oidValue = Impl.SignatureAlgorithm;
signatureAlgorithm = lazySignatureAlgorithm = Oid.FromOidValue (oidValue, OidGroup.SignatureAlgorithm);
}
return signatureAlgorithm;
}
}
public X500DistinguishedName SubjectName {
get {
ThrowIfInvalid ();
X500DistinguishedName subjectName = lazySubjectName;
if (subjectName == null)
subjectName = lazySubjectName = Impl.SubjectName;
return subjectName;
}
}
public string Thumbprint {
get {
byte[] thumbPrint = GetCertHash ();
return thumbPrint.ToHexStringUpper ();
}
}
public int Version {
get {
ThrowIfInvalid ();
int version = lazyVersion;
if (version == 0)
version = lazyVersion = Impl.Version;
return version;
}
}
public static X509ContentType GetCertContentType (byte[] rawData)
{
if (rawData == null || rawData.Length == 0)
throw new ArgumentException (SR.Arg_EmptyOrNullArray, nameof (rawData));
return X509Pal.Instance.GetCertContentType (rawData);
}
public static X509ContentType GetCertContentType (string fileName)
{
if (fileName == null)
throw new ArgumentNullException (nameof (fileName));
// Desktop compat: The desktop CLR expands the filename to a full path for the purpose of performing a CAS permission check. While CAS is not present here,
// we still need to call GetFullPath() so we get the same exception behavior if the fileName is bad.
string fullPath = Path.GetFullPath (fileName);
return X509Pal.Instance.GetCertContentType (fileName);
}
public string GetNameInfo (X509NameType nameType, bool forIssuer)
{
return Impl.GetNameInfo (nameType, forIssuer);
}
public override string ToString ()
{
return base.ToString (fVerbose: true);
}
public override string ToString (bool verbose)
{
if (verbose == false || !IsValid)
return ToString ();
StringBuilder sb = new StringBuilder ();
// Version
sb.AppendLine ("[Version]");
sb.Append (" V");
sb.Append (Version);
// Subject
sb.AppendLine ();
sb.AppendLine ();
sb.AppendLine ("[Subject]");
sb.Append (" ");
sb.Append (SubjectName.Name);
string simpleName = GetNameInfo (X509NameType.SimpleName, false);
if (simpleName.Length > 0) {
sb.AppendLine ();
sb.Append (" ");
sb.Append ("Simple Name: ");
sb.Append (simpleName);
}
string emailName = GetNameInfo (X509NameType.EmailName, false);
if (emailName.Length > 0) {
sb.AppendLine ();
sb.Append (" ");
sb.Append ("Email Name: ");
sb.Append (emailName);
}
string upnName = GetNameInfo (X509NameType.UpnName, false);
if (upnName.Length > 0) {
sb.AppendLine ();
sb.Append (" ");
sb.Append ("UPN Name: ");
sb.Append (upnName);
}
string dnsName = GetNameInfo (X509NameType.DnsName, false);
if (dnsName.Length > 0) {
sb.AppendLine ();
sb.Append (" ");
sb.Append ("DNS Name: ");
sb.Append (dnsName);
}
// Issuer
sb.AppendLine ();
sb.AppendLine ();
sb.AppendLine ("[Issuer]");
sb.Append (" ");
sb.Append (IssuerName.Name);
simpleName = GetNameInfo (X509NameType.SimpleName, true);
if (simpleName.Length > 0) {
sb.AppendLine ();
sb.Append (" ");
sb.Append ("Simple Name: ");
sb.Append (simpleName);
}
emailName = GetNameInfo (X509NameType.EmailName, true);
if (emailName.Length > 0) {
sb.AppendLine ();
sb.Append (" ");
sb.Append ("Email Name: ");
sb.Append (emailName);
}
upnName = GetNameInfo (X509NameType.UpnName, true);
if (upnName.Length > 0) {
sb.AppendLine ();
sb.Append (" ");
sb.Append ("UPN Name: ");
sb.Append (upnName);
}
dnsName = GetNameInfo (X509NameType.DnsName, true);
if (dnsName.Length > 0) {
sb.AppendLine ();
sb.Append (" ");
sb.Append ("DNS Name: ");
sb.Append (dnsName);
}
// Serial Number
sb.AppendLine ();
sb.AppendLine ();
sb.AppendLine ("[Serial Number]");
sb.Append (" ");
sb.AppendLine (SerialNumber);
// NotBefore
sb.AppendLine ();
sb.AppendLine ("[Not Before]");
sb.Append (" ");
sb.AppendLine (FormatDate (NotBefore));
// NotAfter
sb.AppendLine ();
sb.AppendLine ("[Not After]");
sb.Append (" ");
sb.AppendLine (FormatDate (NotAfter));
// Thumbprint
sb.AppendLine ();
sb.AppendLine ("[Thumbprint]");
sb.Append (" ");
sb.AppendLine (Thumbprint);
// Signature Algorithm
sb.AppendLine ();
sb.AppendLine ("[Signature Algorithm]");
sb.Append (" ");
sb.Append (SignatureAlgorithm.FriendlyName);
sb.Append ('(');
sb.Append (SignatureAlgorithm.Value);
sb.AppendLine (")");
// Public Key
sb.AppendLine ();
sb.Append ("[Public Key]");
// It could throw if it's some user-defined CryptoServiceProvider
try {
PublicKey pubKey = PublicKey;
sb.AppendLine ();
sb.Append (" ");
sb.Append ("Algorithm: ");
sb.Append (pubKey.Oid.FriendlyName);
// So far, we only support RSACryptoServiceProvider & DSACryptoServiceProvider Keys
try {
sb.AppendLine ();
sb.Append (" ");
sb.Append ("Length: ");
using (RSA pubRsa = this.GetRSAPublicKey ()) {
if (pubRsa != null) {
sb.Append (pubRsa.KeySize);
}
}
} catch (NotSupportedException) {
}
sb.AppendLine ();
sb.Append (" ");
sb.Append ("Key Blob: ");
sb.AppendLine (pubKey.EncodedKeyValue.Format (true));
sb.Append (" ");
sb.Append ("Parameters: ");
sb.Append (pubKey.EncodedParameters.Format (true));
} catch (CryptographicException) {
}
// Private key
Impl.AppendPrivateKeyInfo (sb);
// Extensions
X509ExtensionCollection extensions = Extensions;
if (extensions.Count > 0) {
sb.AppendLine ();
sb.AppendLine ();
sb.Append ("[Extensions]");
foreach (X509Extension extension in extensions) {
try {
sb.AppendLine ();
sb.Append ("* ");
sb.Append (extension.Oid.FriendlyName);
sb.Append ('(');
sb.Append (extension.Oid.Value);
sb.Append ("):");
sb.AppendLine ();
sb.Append (" ");
sb.Append (extension.Format (true));
} catch (CryptographicException) {
}
}
}
sb.AppendLine ();
return sb.ToString ();
}
public override void Import (byte[] rawData)
{
base.Import (rawData);
}
public override void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
{
base.Import (rawData, password, keyStorageFlags);
}
[CLSCompliantAttribute (false)]
public override void Import (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags)
{
base.Import (rawData, password, keyStorageFlags);
}
public override void Import (string fileName)
{
base.Import (fileName);
}
public override void Import (string fileName, string password, X509KeyStorageFlags keyStorageFlags)
{
base.Import (fileName, password, keyStorageFlags);
}
[CLSCompliantAttribute (false)]
public override void Import (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags)
{
base.Import (fileName, password, keyStorageFlags);
}
#region Mono Implementation
public bool Verify ()
{
return Impl.Verify (this);
}
#endregion
static X509Extension CreateCustomExtensionIfAny (Oid oid)
{
string oidValue = oid.Value;
switch (oidValue) {
case Oids.BasicConstraints:
return X509Pal.Instance.SupportsLegacyBasicConstraintsExtension ?
new X509BasicConstraintsExtension () :
null;
case Oids.BasicConstraints2:
return new X509BasicConstraintsExtension ();
case Oids.KeyUsage:
return new X509KeyUsageExtension ();
case Oids.EnhancedKeyUsage:
return new X509EnhancedKeyUsageExtension ();
case Oids.SubjectKeyIdentifier:
return new X509SubjectKeyIdentifierExtension ();
default:
return null;
}
}
//
// MARTIN CHECK POINT
//
new internal X509Certificate2Impl Impl {
get {
var impl2 = base.Impl as X509Certificate2Impl;
X509Helper.ThrowIfContextInvalid (impl2);
return impl2;
}
}
}
}