File: Base\MS\Internal\IO\Packaging\Certificate.cs
Project: wpf\src\WindowsBase.csproj (WindowsBase)
//-----------------------------------------------------------------------------
//
// <copyright file="Certificate.cs" company="Microsoft">
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// Description:
//  Handles serialization to/from X509 Certificate part (X509v3 = ASN.1 DER format)
//
// History:
//  03/22/2004: BruceMac: Initial Implementation
//
//-----------------------------------------------------------------------------
 
using System;
using System.Diagnostics;                               // for Assert
using System.Security.Cryptography.X509Certificates;
using System.Windows;                                   // For Exception strings - SRID
using System.IO.Packaging;      
using System.IO;                                        // for Stream
using MS.Internal;                                      // For ContentType
using MS.Internal.WindowsBase;
 
namespace MS.Internal.IO.Packaging
{
    /// <summary>
    /// CertificatePart
    /// </summary>
    internal class CertificatePart
    {
        #region Internal Members
        //------------------------------------------------------
        //
        //  Internal Properties
        //
        //------------------------------------------------------
        /// <summary>
        /// Type of relationship to a Certificate Part
        /// </summary>
        static internal string RelationshipType
        {
            get
            {
                return _certificatePartRelationshipType;
            }
        }
 
        /// <summary>
        /// Prefix of auto-generated Certificate Part names
        /// </summary>
        static internal string PartNamePrefix
        {
            get
            {
                return _certificatePartNamePrefix;
            }
        }
 
        /// <summary>
        /// Extension of Certificate Part file names
        /// </summary>
        static internal string PartNameExtension
        {
            get
            {
                return _certificatePartNameExtension;
            }
        }
 
        /// <summary>
        /// ContentType of Certificate Parts
        /// </summary>
        static internal ContentType ContentType
        {
            get
            {
                return _certificatePartContentType;
            }
        }
 
        internal Uri Uri
        {
            get
            {
                return _part.Uri;
            }
        }
 
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
        /// <summary>
        /// Certificate to associate with this Certificate Part
        /// </summary>
        /// <value></value>
        /// <exception cref="FileFormatException">stream is too large</exception>
        internal X509Certificate2 GetCertificate()
        {
            // lazy init
            if (_certificate == null)
            {
                // obtain from the part
                using (Stream s = _part.GetStream())
                {
                    if (s.Length > 0)
                    {
                        // throw if stream is beyond any reasonable length
                        if (s.Length > _maximumCertificateStreamLength)
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));
 
                        // X509Certificate constructor desires a byte array
                        Byte[] byteArray = new Byte[s.Length];
                        PackagingUtilities.ReliableRead(s, byteArray, 0, (int)s.Length);
                        _certificate = new X509Certificate2(byteArray);
                    }
                }
            }
            return _certificate;
        }
 
        internal void SetCertificate(X509Certificate2 certificate)
        {
            if (certificate == null)
                throw new ArgumentNullException("certificate");
 
            _certificate = certificate;
 
            // persist to the part
            Byte[] byteArray = _certificate.GetRawCertData();
 
            // FileMode.Create will ensure that the stream will shrink if overwritten
            using (Stream s = _part.GetStream(FileMode.Create, FileAccess.Write))
            {
                s.Write(byteArray, 0, byteArray.Length);
            }
        }
 
        /// <summary>
        /// CertificatePart constructor
        /// </summary>
        internal CertificatePart(Package container, Uri partName)
        {
            if (container == null)
                throw new ArgumentNullException("container");
            
            if (partName == null)
                throw new ArgumentNullException("partName");
 
            partName = PackUriHelper.ValidatePartUri(partName);
            
            // create if not found
            if (container.PartExists(partName))
            {
                // open the part
                _part = container.GetPart(partName);
 
                // ensure the part is of the expected type
                if (_part.ValidatedContentType.AreTypeAndSubTypeEqual(_certificatePartContentType) == false)
                    throw new FileFormatException(SR.Get(SRID.CertificatePartContentTypeMismatch));
            }
            else
            {
                // create the part
                _part = container.CreatePart(partName, _certificatePartContentType.ToString());
            }
        }
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
        private PackagePart             _part;          // part that houses the certificate
        private X509Certificate2       _certificate;   // certificate itself
 
        // certificate part constants
        private static readonly ContentType _certificatePartContentType =
            new ContentType("application/vnd.openxmlformats-package.digital-signature-certificate");
        private static readonly string _certificatePartNamePrefix = "/package/services/digital-signature/certificate/";
        private static readonly string _certificatePartNameExtension = ".cer";
        private static readonly string _certificatePartRelationshipType = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/certificate";
        private static long             _maximumCertificateStreamLength = 0x40000;   // 4MB
        #endregion Private Members
    }
}