1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be 3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file. 4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/base/asn1_util.h" 6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace net { 8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace asn1 { 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ParseElement(base::StringPiece* in, 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen unsigned tag_value, 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::StringPiece* out, 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen unsigned *out_header_len) { 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const uint8* data = reinterpret_cast<const uint8*>(in->data()); 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (in->size() < 2) 18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (static_cast<unsigned char>(data[0]) != tag_value) 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen size_t len = 0; 24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if ((data[1] & 0x80) == 0) { 25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // short form length 26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (out_header_len) 27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *out_header_len = 2; 28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen len = static_cast<size_t>(data[1]) + 2; 29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // long form length 31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const unsigned num_bytes = data[1] & 0x7f; 32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (num_bytes == 0 || num_bytes > 2) 33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (in->size() < 2 + num_bytes) 35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen len = data[2]; 37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (num_bytes == 2) { 38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (len == 0) { 39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // the length encoding must be minimal. 40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen len <<= 8; 43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen len += data[3]; 44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (len < 128) { 46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // the length should have been encoded in short form. This distinguishes 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // DER from BER encoding. 48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (out_header_len) 51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *out_header_len = 2 + num_bytes; 52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen len += 2 + num_bytes; 53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (in->size() < len) 56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (out) 58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *out = base::StringPiece(in->data(), len); 59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen in->remove_prefix(len); 60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return true; 61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool GetElement(base::StringPiece* in, 64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen unsigned tag_value, 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::StringPiece* out) { 66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen unsigned header_len; 67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!ParseElement(in, tag_value, out, &header_len)) 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (out) 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen out->remove_prefix(header_len); 71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return true; 72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ExtractSPKIFromDERCert(base::StringPiece cert, 75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::StringPiece* spki_out) { 76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // From RFC 5280, section 4.1 77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Certificate ::= SEQUENCE { 78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // tbsCertificate TBSCertificate, 79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // signatureAlgorithm AlgorithmIdentifier, 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // signatureValue BIT STRING } 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // TBSCertificate ::= SEQUENCE { 83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // version [0] EXPLICIT Version DEFAULT v1, 84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // serialNumber CertificateSerialNumber, 85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // signature AlgorithmIdentifier, 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // issuer Name, 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // validity Validity, 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // subject Name, 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // subjectPublicKeyInfo SubjectPublicKeyInfo, 90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::StringPiece certificate; 92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!asn1::GetElement(&cert, asn1::kSEQUENCE, &certificate)) 93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::StringPiece tbs_certificate; 96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!asn1::GetElement(&certificate, asn1::kSEQUENCE, &tbs_certificate)) 97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The version is optional, so a failure to parse it is fine. 100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen asn1::GetElement(&tbs_certificate, 101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen asn1::kCompound | asn1::kContextSpecific | 0, 102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NULL); 103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // serialNumber 105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!asn1::GetElement(&tbs_certificate, asn1::kINTEGER, NULL)) 106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // signature 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL)) 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // issuer 111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL)) 112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // validity 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL)) 115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // subject 117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL)) 118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // subjectPublicKeyInfo 120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!asn1::ParseElement(&tbs_certificate, asn1::kSEQUENCE, spki_out, NULL)) 121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return true; 123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace asn1 126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace net 128