diff --git a/src/core/iTextSharp/text/pdf/IOcspClient.cs b/src/core/iTextSharp/text/pdf/IOcspClient.cs new file mode 100644 index 0000000..32f647f --- /dev/null +++ b/src/core/iTextSharp/text/pdf/IOcspClient.cs @@ -0,0 +1,64 @@ +using System; +/* + * $Id: OcspClient.java 3959 2009-06-09 08:31:05Z blowagie $ + * + * Copyright 2009 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2009 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Interface for the OCSP Client. + * @since 2.1.6 + */ + public interface IOcspClient { + /** + * Gets an encoded byte array. + * @return a byte array + */ + byte[] GetEncoded(); + } +} diff --git a/src/core/iTextSharp/text/pdf/ITSAClient.cs b/src/core/iTextSharp/text/pdf/ITSAClient.cs new file mode 100644 index 0000000..ffcfff7 --- /dev/null +++ b/src/core/iTextSharp/text/pdf/ITSAClient.cs @@ -0,0 +1,80 @@ +using System; +/* + * $Id: TSAClient.java 3959 2009-06-09 08:31:05Z blowagie $ + * + * Copyright 2009 Martin Brunecky + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2009 by Martin Brunecky. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Time Stamp Authority client (caller) interface. + *

+ * Interface used by the PdfPKCS7 digital signature builder to call + * Time Stamp Authority providing RFC 3161 compliant time stamp token. + * @author Martin Brunecky, 07/17/2007 + * @since 2.1.6 + */ + public interface ITSAClient { + /** + * Get the time stamp token size estimate. + * Implementation must return value large enough to accomodate the entire token + * returned by getTimeStampToken() _prior_ to actual getTimeStampToken() call. + * @return an estimate of the token size + */ + int GetTokenSizeEstimate(); + + /** + * Get RFC 3161 timeStampToken. + * Method may return null indicating that timestamp should be skipped. + * @param caller PdfPKCS7 - calling PdfPKCS7 instance (in case caller needs it) + * @param imprint byte[] - data imprint to be time-stamped + * @return byte[] - encoded, TSA signed data of the timeStampToken + * @throws Exception - TSA request failed + */ + byte[] GetTimeStampToken(PdfPKCS7 caller, byte[] imprint); + } +} \ No newline at end of file diff --git a/src/core/iTextSharp/text/pdf/OcspClientBouncyCastle.cs b/src/core/iTextSharp/text/pdf/OcspClientBouncyCastle.cs new file mode 100644 index 0000000..aabf4b7 --- /dev/null +++ b/src/core/iTextSharp/text/pdf/OcspClientBouncyCastle.cs @@ -0,0 +1,160 @@ +using System; +using System.IO; +using System.Collections; +using System.Net; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Ocsp; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.Ocsp; +/* + * $Id: OcspClientBouncyCastle.java 3959 2009-06-09 08:31:05Z blowagie $ + * + * Copyright 2009 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2009 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * OcspClient implementation using BouncyCastle. + * @author psoares + * @since 2.1.6 + */ + public class OcspClientBouncyCastle : IOcspClient { + /** root certificate */ + private X509Certificate rootCert; + /** check certificate */ + private X509Certificate checkCert; + /** OCSP URL */ + private String url; + + /** + * Creates an instance of an OcspClient that will be using BouncyCastle. + * @param checkCert the check certificate + * @param rootCert the root certificate + * @param url the OCSP URL + */ + public OcspClientBouncyCastle(X509Certificate checkCert, X509Certificate rootCert, String url) { + this.checkCert = checkCert; + this.rootCert = rootCert; + this.url = url; + } + + /** + * Generates an OCSP request using BouncyCastle. + * @param issuerCert certificate of the issues + * @param serialNumber serial number + * @return an OCSP request + * @throws OCSPException + * @throws IOException + */ + private static OcspReq GenerateOCSPRequest(X509Certificate issuerCert, BigInteger serialNumber) { + // Generate the id for the certificate we are looking for + CertificateID id = new CertificateID(CertificateID.HashSha1, issuerCert, serialNumber); + + // basic request generation with nonce + OcspReqGenerator gen = new OcspReqGenerator(); + + gen.AddRequest(id); + + // create details for nonce extension + ArrayList oids = new ArrayList(); + ArrayList values = new ArrayList(); + + oids.Add(OcspObjectIdentifiers.PkixOcspNonce); + values.Add(new X509Extension(false, new DerOctetString(new DerOctetString(PdfEncryption.CreateDocumentId()).GetEncoded()))); + + gen.SetRequestExtensions(new X509Extensions(oids, values)); + + return gen.Generate(); + } + + /** + * @return a byte array + * @see com.lowagie.text.pdf.OcspClient#getEncoded() + */ + public byte[] GetEncoded() { + OcspReq request = GenerateOCSPRequest(rootCert, checkCert.SerialNumber); + byte[] array = request.GetEncoded(); + HttpWebRequest con = (HttpWebRequest)WebRequest.Create(url); + con.ContentLength = array.Length; + con.ContentType = "application/ocsp-request"; + con.Accept = "application/ocsp-response"; + Stream outp = con.GetRequestStream(); + outp.Write(array, 0, array.Length); + outp.Close(); + HttpWebResponse response = (HttpWebResponse)con.GetResponse(); + if (response.StatusCode != HttpStatusCode.OK) + throw new IOException("Invalid HTTP response: " + (int)response.StatusCode); + Stream inp = response.GetResponseStream(); + OcspResp ocspResponse = new OcspResp(inp); + inp.Close(); + response.Close(); + + if (ocspResponse.Status != 0) + throw new IOException("Invalid status: " + ocspResponse.Status); + BasicOcspResp basicResponse = (BasicOcspResp) ocspResponse.GetResponseObject(); + if (basicResponse != null) { + SingleResp[] responses = basicResponse.Responses; + if (responses.Length == 1) { + SingleResp resp = responses[0]; + Object status = resp.GetCertStatus(); + if (status == CertificateStatus.Good) { + return basicResponse.GetEncoded(); + } + else if (status is Org.BouncyCastle.Ocsp.RevokedStatus) { + throw new IOException("OCSP Status is revoked!"); + } + else { + throw new IOException("OCSP Status is unknown!"); + } + } + } + return null; + } + } +} \ No newline at end of file diff --git a/src/core/iTextSharp/text/pdf/TSAClientBouncyCastle.cs b/src/core/iTextSharp/text/pdf/TSAClientBouncyCastle.cs new file mode 100644 index 0000000..5d003cd --- /dev/null +++ b/src/core/iTextSharp/text/pdf/TSAClientBouncyCastle.cs @@ -0,0 +1,221 @@ +using System; +using System.IO; +using System.Collections; +using System.Net; +using System.Text; +using System.util; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Tsp; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.Cmp; +using Org.BouncyCastle.Asn1.Tsp; +/* + * $Id: TSAClientBouncyCastle.java 3973 2009-06-16 10:30:31Z psoares33 $ + * + * Copyright 2009 Martin Brunecky, Aiken Sam + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2009 by Martin Brunecky. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Time Stamp Authority Client interface implementation using Bouncy Castle + * org.bouncycastle.tsp package. + *

+ * Created by Aiken Sam, 2006-11-15, refactored by Martin Brunecky, 07/15/2007 + * for ease of subclassing. + *

+ * @since 2.1.6 + */ + public class TSAClientBouncyCastle : ITSAClient { + /** URL of the Time Stamp Authority */ + protected String tsaURL; + /** TSA Username */ + protected String tsaUsername; + /** TSA password */ + protected String tsaPassword; + /** Estimate of the received time stamp token */ + protected int tokSzEstimate; + + /** + * Creates an instance of a TSAClient that will use BouncyCastle. + * @param url String - Time Stamp Authority URL (i.e. "http://tsatest1.digistamp.com/TSA") + */ + public TSAClientBouncyCastle(String url) : this(url, null, null, 4096) { + } + + /** + * Creates an instance of a TSAClient that will use BouncyCastle. + * @param url String - Time Stamp Authority URL (i.e. "http://tsatest1.digistamp.com/TSA") + * @param username String - user(account) name + * @param password String - password + */ + public TSAClientBouncyCastle(String url, String username, String password) : this(url, username, password, 4096) { + } + + /** + * Constructor. + * Note the token size estimate is updated by each call, as the token + * size is not likely to change (as long as we call the same TSA using + * the same imprint length). + * @param url String - Time Stamp Authority URL (i.e. "http://tsatest1.digistamp.com/TSA") + * @param username String - user(account) name + * @param password String - password + * @param tokSzEstimate int - estimated size of received time stamp token (DER encoded) + */ + public TSAClientBouncyCastle(String url, String username, String password, int tokSzEstimate) { + this.tsaURL = url; + this.tsaUsername = username; + this.tsaPassword = password; + this.tokSzEstimate = tokSzEstimate; + } + + /** + * Get the token size estimate. + * Returned value reflects the result of the last succesfull call, padded + * @return an estimate of the token size + */ + public int GetTokenSizeEstimate() { + return tokSzEstimate; + } + + /** + * Get RFC 3161 timeStampToken. + * Method may return null indicating that timestamp should be skipped. + * @param caller PdfPKCS7 - calling PdfPKCS7 instance (in case caller needs it) + * @param imprint byte[] - data imprint to be time-stamped + * @return byte[] - encoded, TSA signed data of the timeStampToken + * @throws Exception - TSA request failed + * @see com.lowagie.text.pdf.TSAClient#getTimeStampToken(com.lowagie.text.pdf.PdfPKCS7, byte[]) + */ + public byte[] GetTimeStampToken(PdfPKCS7 caller, byte[] imprint) { + return GetTimeStampToken(imprint); + } + + /** + * Get timestamp token - Bouncy Castle request encoding / decoding layer + */ + protected internal byte[] GetTimeStampToken(byte[] imprint) { + byte[] respBytes = null; + // Setup the time stamp request + TimeStampRequestGenerator tsqGenerator = new TimeStampRequestGenerator(); + tsqGenerator.SetCertReq(true); + // tsqGenerator.setReqPolicy("1.3.6.1.4.1.601.10.3.1"); + BigInteger nonce = BigInteger.ValueOf(DateTime.Now.Ticks + Environment.TickCount); + TimeStampRequest request = tsqGenerator.Generate(X509ObjectIdentifiers.IdSha1.Id, imprint, nonce); + byte[] requestBytes = request.GetEncoded(); + + // Call the communications layer + respBytes = GetTSAResponse(requestBytes); + + // Handle the TSA response + TimeStampResponse response = new TimeStampResponse(respBytes); + + // validate communication level attributes (RFC 3161 PKIStatus) + response.Validate(request); + PkiFailureInfo failure = response.GetFailInfo(); + int value = (failure == null) ? 0 : failure.IntValue; + if (value != 0) { + // @todo: Translate value of 15 error codes defined by PKIFailureInfo to string + throw new Exception("Invalid TSA '" + tsaURL + "' response, code " + value); + } + // @todo: validate the time stap certificate chain (if we want + // assure we do not sign using an invalid timestamp). + + // extract just the time stamp token (removes communication status info) + TimeStampToken tsToken = response.TimeStampToken; + if (tsToken == null) { + throw new Exception("TSA '" + tsaURL + "' failed to return time stamp token: " + response.GetStatusString()); + } + TimeStampTokenInfo info = tsToken.TimeStampInfo; // to view details + byte[] encoded = tsToken.GetEncoded(); + + // Update our token size estimate for the next call (padded to be safe) + this.tokSzEstimate = encoded.Length + 32; + return encoded; + } + + /** + * Get timestamp token - communications layer + * @return - byte[] - TSA response, raw bytes (RFC 3161 encoded) + */ + protected internal virtual byte[] GetTSAResponse(byte[] requestBytes) { + HttpWebRequest con = (HttpWebRequest)WebRequest.Create(tsaURL); + con.ContentLength = requestBytes.Length; + con.ContentType = "application/timestamp-query"; + con.TransferEncoding = "binary"; + if ((tsaUsername != null) && !tsaUsername.Equals("") ) { + string authInfo = tsaUsername + ":" + tsaPassword; + authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo)); + con.Headers["Authorization"] = "Basic " + authInfo; + } + Stream outp = con.GetRequestStream(); + outp.Write(requestBytes, 0, requestBytes.Length); + outp.Close(); + HttpWebResponse response = (HttpWebResponse)con.GetResponse(); + if (response.StatusCode != HttpStatusCode.OK) + throw new IOException("Invalid HTTP response: " + (int)response.StatusCode); + Stream inp = response.GetResponseStream(); + + MemoryStream baos = new MemoryStream(); + byte[] buffer = new byte[1024]; + int bytesRead = 0; + while ((bytesRead = inp.Read(buffer, 0, buffer.Length)) > 0) { + baos.Write(buffer, 0, bytesRead); + } + inp.Close(); + response.Close(); + byte[] respBytes = baos.ToArray(); + + String encoding = response.ContentEncoding; + if (encoding != null && Util.EqualsIgnoreCase(encoding, "base64")) { + respBytes = Convert.FromBase64String(Encoding.ASCII.GetString(respBytes)); + } + return respBytes; + } + } +} \ No newline at end of file