Bug 1029341: Factor out decoding of certificate/OCSP extensions, r=keeler

--HG--
extra : rebase_source : a1d66b75838e9dfad486f5654db6d977e5c1d97a
extra : histedit_source : 34e05d8b3d94500b9cb4f1e311f8fe526b97ba6e
This commit is contained in:
Brian Smith 2014-06-24 21:52:50 -07:00
parent adfff88e33
commit bf76dd549d
2 changed files with 83 additions and 45 deletions

View File

@ -661,6 +661,74 @@ OptionalVersion(Input& input, /*out*/ Version& version)
return Success;
}
template <typename ExtensionHandler>
inline Result
OptionalExtensions(Input& input, uint8_t tag, ExtensionHandler extensionHandler)
{
if (!input.Peek(tag)) {
return Success;
}
Input extensions;
{
Input tagged;
if (ExpectTagAndGetValue(input, tag, tagged) != Success) {
return Failure;
}
if (ExpectTagAndGetValue(tagged, SEQUENCE, extensions) != Success) {
return Failure;
}
if (End(tagged) != Success) {
return Failure;
}
}
// Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
//
// TODO(bug 997994): According to the specification, there should never be
// an empty sequence of extensions but we've found OCSP responses that have
// that (see bug 991898).
while (!extensions.AtEnd()) {
Input extension;
if (ExpectTagAndGetValue(extensions, SEQUENCE, extension)
!= Success) {
return Failure;
}
// Extension ::= SEQUENCE {
// extnID OBJECT IDENTIFIER,
// critical BOOLEAN DEFAULT FALSE,
// extnValue OCTET STRING
// }
Input extnID;
if (ExpectTagAndGetValue(extension, OIDTag, extnID) != Success) {
return Failure;
}
bool critical;
if (OptionalBoolean(extension, false, critical) != Success) {
return Failure;
}
SECItem extnValue;
if (ExpectTagAndGetValue(extension, OCTET_STRING, extnValue)
!= Success) {
return Failure;
}
if (End(extension) != Success) {
return Failure;
}
bool understood = false;
if (extensionHandler(extnID, extnValue, understood) != Success) {
return Failure;
}
if (critical && !understood) {
return Fail(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
}
}
return Success;
}
// Parses a SEQUENCE into tbs and then parses an AlgorithmIdentifier followed
// by a BIT STRING into signedData. This handles the commonality between
// parsing the signed/signature fields of certificates and OCSP responses. In

View File

@ -179,7 +179,9 @@ static inline der::Result ResponseData(
/*const*/ SECItem* certs, size_t numCerts);
static inline der::Result SingleResponse(der::Input& input,
Context& context);
static inline der::Result CheckExtensionsForCriticality(der::Input&);
static der::Result ExtensionNotUnderstood(der::Input& extnID,
const SECItem& extnValue,
/*out*/ bool& understood);
static inline der::Result CertID(der::Input& input,
const Context& context,
/*out*/ bool& match);
@ -531,14 +533,9 @@ ResponseData(der::Input& input, Context& context,
return der::Failure;
}
if (!input.AtEnd()) {
if (der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
CheckExtensionsForCriticality) != der::Success) {
return der::Failure;
}
}
return der::Success;
return der::OptionalExtensions(input,
der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
ExtensionNotUnderstood);
}
// SingleResponse ::= SEQUENCE {
@ -656,11 +653,11 @@ SingleResponse(der::Input& input, Context& context)
context.expired = true;
}
if (!input.AtEnd()) {
if (der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
CheckExtensionsForCriticality) != der::Success) {
return der::Failure;
}
if (der::OptionalExtensions(input,
der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
ExtensionNotUnderstood)
!= der::Success) {
return der::Failure;
}
if (context.thisUpdate) {
@ -836,41 +833,14 @@ KeyHash(const SECItem& subjectPublicKeyInfo, /*out*/ uint8_t* hashBuf,
return Success;
}
// Extension ::= SEQUENCE {
// extnID OBJECT IDENTIFIER,
// critical BOOLEAN DEFAULT FALSE,
// extnValue OCTET STRING
// }
static der::Result
CheckExtensionForCriticality(der::Input& input)
der::Result
ExtensionNotUnderstood(der::Input& /*extnID*/, const SECItem& /*extnValue*/,
/*out*/ bool& understood)
{
// TODO: maybe we should check the syntax of the OID value
if (ExpectTagAndSkipValue(input, der::OIDTag) != der::Success) {
return der::Failure;
}
// The only valid explicit encoding of the value is TRUE, so don't even
// bother parsing it, since we're going to fail either way.
if (input.Peek(der::BOOLEAN)) {
return der::Fail(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
}
input.SkipToEnd();
understood = false;
return der::Success;
}
// Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
static der::Result
CheckExtensionsForCriticality(der::Input& input)
{
// TODO(bug 997994): some responders include an empty SEQUENCE OF
// Extension, which is invalid (der::MayBeEmpty should really be
// der::MustNotBeEmpty).
return der::NestedOf(input, der::SEQUENCE, der::SEQUENCE,
der::EmptyAllowed::Yes, CheckExtensionForCriticality);
}
// 1. The certificate identified in a received response corresponds to
// the certificate that was identified in the corresponding request;
// 2. The signature on the response is valid;