Esempio n. 1
0
// BasicOCSPResponse       ::= SEQUENCE {
//    tbsResponseData      ResponseData,
//    signatureAlgorithm   AlgorithmIdentifier,
//    signature            BIT STRING,
//    certs            [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
der::Result
BasicResponse(der::Input& input, Context& context)
{
  der::Input::Mark mark(input.GetMark());

  uint16_t length;
  if (der::ExpectTagAndGetLength(input, der::SEQUENCE, length)
        != der::Success) {
    return der::Failure;
  }

  // The signature covers the entire DER encoding of tbsResponseData, including
  // the beginning tag and length. However, when we're parsing tbsResponseData,
  // we want to strip off the tag and length because we don't need it after
  // we've confirmed it's there and figured out what length it is.

  der::Input tbsResponseData;

  if (input.Skip(length, tbsResponseData) != der::Success) {
    return der::Failure;
  }

  CERTSignedData signedData;

  input.GetSECItem(siBuffer, mark, signedData.data);

  if (der::Nested(input, der::SEQUENCE,
                  bind(der::AlgorithmIdentifier, _1,
                       ref(signedData.signatureAlgorithm))) != der::Success) {
    return der::Failure;
  }

  if (der::Skip(input, der::BIT_STRING, signedData.signature) != der::Success) {
    return der::Failure;
  }
  if (signedData.signature.len == 0) {
    return der::Fail(SEC_ERROR_OCSP_BAD_SIGNATURE);
  }
  unsigned int unusedBitsAtEnd = signedData.signature.data[0];
  // XXX: Really the constraint should be that unusedBitsAtEnd must be less
  // than 7. But, we suspect there are no valid OCSP response signatures with
  // non-zero unused bits. It seems like NSS assumes this in various places, so
  // we enforce it. If we find compatibility issues, we'll know we're wrong.
  if (unusedBitsAtEnd != 0) {
    return der::Fail(SEC_ERROR_OCSP_BAD_SIGNATURE);
  }
  ++signedData.signature.data;
  --signedData.signature.len;
  signedData.signature.len = (signedData.signature.len << 3); // Bytes to bits

  // Parse certificates, if any

  SECItem certs[8];
  size_t numCerts = 0;

  if (!input.AtEnd()) {
    // We ignore the lengths of the wrappers because we'll detect bad lengths
    // during parsing--too short and we'll run out of input for parsing a cert,
    // and too long and we'll have leftover data that won't parse as a cert.

    // [0] wrapper
    if (der::ExpectTagAndIgnoreLength(
          input, der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0)
        != der::Success) {
      return der::Failure;
    }

    // SEQUENCE wrapper
    if (der::ExpectTagAndIgnoreLength(input, der::SEQUENCE) != der::Success) {
      return der::Failure;
    }

    // sequence of certificates
    while (!input.AtEnd()) {
      if (numCerts == PR_ARRAY_SIZE(certs)) {
        return der::Fail(SEC_ERROR_BAD_DER);
      }

      // Unwrap the SEQUENCE that contains the certificate, which is itself a
      // SEQUENCE.
      der::Input::Mark mark(input.GetMark());
      if (der::Skip(input, der::SEQUENCE) != der::Success) {
        return der::Failure;
      }

      input.GetSECItem(siBuffer, mark, certs[numCerts]);
      ++numCerts;
    }
  }

  return ResponseData(tbsResponseData, context, signedData, certs, numCerts);
}