summaryrefslogtreecommitdiffstats
path: root/net/base/x509_certificate.cc
diff options
context:
space:
mode:
authorrsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-17 02:59:34 +0000
committerrsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-17 02:59:34 +0000
commit76c0613c3feb32332f67a1b6a273102d2c064801 (patch)
tree2fc1f85917f0b9cda5b8fb2ae9fa5c6618d0398e /net/base/x509_certificate.cc
parentda5ec5315e9b93fd5cfb011367327aef148acd70 (diff)
downloadchromium_src-76c0613c3feb32332f67a1b6a273102d2c064801.zip
chromium_src-76c0613c3feb32332f67a1b6a273102d2c064801.tar.gz
chromium_src-76c0613c3feb32332f67a1b6a273102d2c064801.tar.bz2
Add support for parsing certificate formats other than raw, DER-encoded certificates - specifically formats that represent collections of certificates. The certificate format can now be specified as an explicit format, or as a bit-mask of formats that are acceptable/expected, with the first parsable format winning.
This is one half of a commit to address BUG #37142, with the second half involving connecting this through the X509UserCertHandler and the actual UI. R=wtc BUG=37142 TEST=X509CertificateParseTest* and PEMTokenizerTest.* Review URL: http://codereview.chromium.org/2819018 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52799 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base/x509_certificate.cc')
-rw-r--r--net/base/x509_certificate.cc89
1 files changed, 89 insertions, 0 deletions
diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc
index f5b28a6..1230f27 100644
--- a/net/base/x509_certificate.cc
+++ b/net/base/x509_certificate.cc
@@ -15,7 +15,9 @@
#include "base/histogram.h"
#include "base/logging.h"
#include "base/singleton.h"
+#include "base/string_piece.h"
#include "base/time.h"
+#include "net/base/pem_tokenizer.h"
namespace net {
@@ -31,6 +33,18 @@ bool IsNullFingerprint(const SHA1Fingerprint& fingerprint) {
return true;
}
+// Indicates the order to use when trying to decode binary data, which is
+// based on (speculation) as to what will be most common -> least common
+const X509Certificate::Format kFormatDecodePriority[] = {
+ X509Certificate::FORMAT_DER,
+ X509Certificate::FORMAT_PKCS7
+};
+
+// The PEM block header used for DER certificates
+const char kCertificateHeader[] = "CERTIFICATE";
+// The PEM block header used for PKCS#7 data
+const char kPKCS7Header[] = "PKCS7";
+
} // namespace
// static
@@ -186,6 +200,81 @@ X509Certificate* X509Certificate::CreateFromBytes(const char* data,
return cert;
}
+CertificateList X509Certificate::CreateCertificateListFromBytes(
+ const char* data, int length, int format) {
+ OSCertHandles certificates;
+
+ // Try each of the formats, in order of parse preference, to see if |data|
+ // contains the binary representation of a Format.
+ for (size_t i = 0; certificates.empty() &&
+ i < arraysize(kFormatDecodePriority); ++i) {
+ if (format & kFormatDecodePriority[i])
+ certificates = CreateOSCertHandlesFromBytes(data, length,
+ kFormatDecodePriority[i]);
+ }
+
+ // No certs were read. Check to see if it is in a PEM-encoded form.
+ if (certificates.empty()) {
+ base::StringPiece data_string(data, length);
+ std::vector<std::string> pem_headers;
+
+ // To maintain compatibility with NSS/Firefox, CERTIFICATE is a universally
+ // valid PEM block header for any format.
+ pem_headers.push_back(kCertificateHeader);
+ if (format & FORMAT_PKCS7)
+ pem_headers.push_back(kPKCS7Header);
+
+ PEMTokenizer pem_tok(data_string, pem_headers);
+ while (pem_tok.GetNext()) {
+ std::string decoded(pem_tok.data());
+
+ OSCertHandle handle = NULL;
+ if (format & FORMAT_PEM)
+ handle = CreateOSCertHandleFromBytes(decoded.c_str(), decoded.size());
+ if (handle != NULL) {
+ // Parsed a DER encoded certificate. All PEM blocks that follow must
+ // also be DER encoded certificates wrapped inside of PEM blocks.
+ format = FORMAT_PEM;
+ certificates.push_back(handle);
+ continue;
+ }
+
+ // If the first block failed to parse as a DER certificate, and
+ // formats other than PEM are acceptable, check to see if the decoded
+ // data is one of the accepted formats.
+ if (format & ~FORMAT_PEM) {
+ for (size_t i = 0; certificates.empty() &&
+ i < arraysize(kFormatDecodePriority); ++i) {
+ if (format & kFormatDecodePriority[i]) {
+ certificates = CreateOSCertHandlesFromBytes(decoded.c_str(),
+ decoded.size(), kFormatDecodePriority[i]);
+ }
+ }
+ }
+
+ // Stop parsing after the first block for any format but a sequence of
+ // PEM-encoded DER certificates. The case of FORMAT_PEM is handled
+ // above, and continues processing until a certificate fails to parse.
+ break;
+ }
+ }
+
+ CertificateList results;
+ // No certificates parsed.
+ if (certificates.empty())
+ return results;
+
+ for (OSCertHandles::iterator it = certificates.begin();
+ it != certificates.end(); ++it) {
+ X509Certificate* result = CreateFromHandle(*it, SOURCE_LONE_CERT_IMPORT,
+ OSCertHandles());
+ results.push_back(scoped_refptr<X509Certificate>(result));
+ FreeOSCertHandle(*it);
+ }
+
+ return results;
+}
+
X509Certificate::X509Certificate(OSCertHandle cert_handle,
Source source,
const OSCertHandles& intermediates)