certificate_model: migrate to crypto/hash APIs

MERGED2026components/certificate_modelcrypto
2026. 8. 29.DonghanPark 프로필 이미지DonghanPark

Chromium의 //crypto 라이브러리 API 개편 작업으로, components/certificate_model 내에서 사용하던 구형 해시 API(crypto/sha2.h)를 새로운 해시 API(crypto/hash.h)로 마이그레이션했습니다.

문제 설명

Chromium에서는 암호화 관련 API를 도메인별 하위 네임스페이스(crypto::hash, crypto::hmac 등)로 정리하고 인터페이스를 통일하기 위한 마이그레이션 작업이 진행되고 있습니다.

  • 상위 작업인 Issue 374310081(hash 인터페이스 개편)과 Issue 374334448(hmac 인터페이스 개편)에서 새 API가 만들어졌고 이에 맞춰 코드베이스 전체의 호출부를 교체하는 마이그레이션(Issue 372283556)이 진행 중입니다.
  • 기존 crypto/sha2.hcrypto::SHA256Hash()는 평평한 crypto 네임스페이스에 놓여 있고 네이밍도 예전 스타일을 따르고 있었습니다.
  • components/certificate_model/x509_certificate_model_base.cc에서도 인증서 데이터(Certificate Data)와 SPKI(Subject Public Key Info)의 SHA-256 해시를 계산할 때 이 구형 API를 쓰고 있어 교체가 필요했습니다.
// 구 API (crypto/sha2.h)
namespace crypto {
  CRYPTO_EXPORT std::array<uint8_t, kSHA256Length> SHA256Hash(base::span<const uint8_t> input);
}

// 신 API (crypto/hash.h)
namespace crypto::hash {
  CRYPTO_EXPORT std::array<uint8_t, kSha256Size> Sha256(base::span<const uint8_t> data);
}

해결 내용

components/certificate_model/x509_certificate_model_base.cc에서 crypto/sha2.h 헤더 include를 crypto/hash.h로 교체하고, crypto::SHA256Hash() 호출부를 신규 API인 crypto::hash::Sha256()으로 수정했습니다.

  1. 헤더 include 교체: crypto/sha2.hcrypto/hash.h
  2. X509CertificateModelBase::HashCertSHA256() 수정
  3. X509CertificateModelBase::HashSpkiSHA256() 수정
  4. 코드 포맷팅: git cl format으로 Chromium C++ 스타일 가이드에 맞게 줄바꿈 정리

주요 변경 내용

--- a/components/certificate_model/x509_certificate_model_base.cc
+++ b/components/certificate_model/x509_certificate_model_base.cc
@@ -15,7 +15,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/string_view_util.h"
 #include "components/strings/grit/components_strings.h"
-#include "crypto/sha2.h"
+#include "crypto/hash.h"
 #include "net/cert/qwac.h"
 #include "net/cert/time_conversions.h"
 #include "net/cert/x509_util.h"
@@ -351,8 +351,8 @@ OptionalStringOrError X509CertificateModelBase::GetSubjectOrgUnitName() const {
 }
 
 std::string X509CertificateModelBase::HashCertSHA256() const {
-  auto hash =
-      crypto::SHA256Hash(net::x509_util::CryptoBufferAsSpan(cert_data_.get()));
+  auto hash = crypto::hash::Sha256(
+      net::x509_util::CryptoBufferAsSpan(cert_data_.get()));
   return base::HexEncodeLower(hash);
 }
 
@@ -382,7 +382,7 @@ std::string X509CertificateModelBase::GetTitle() const {
 
 std::string X509CertificateModelBase::HashSpkiSHA256() const {
   CHECK(is_valid());
-  auto hash = crypto::SHA256Hash(tbs_.spki_tlv);
+  auto hash = crypto::hash::Sha256(tbs_.spki_tlv);
   return base::HexEncodeLower(hash);
 }

테스트 방법

  1. 단위 테스트(Unit Test) 실행
    components_unittests 타깃의 certificate model 관련 테스트를 실행해 기존 동작에 영향이 없는지 확인했습니다.

    autoninja -C out/Default components_unittests
    out/Default/components_unittests --gtest_filter="*CertificateModel*"
  2. Gerrit LUCI CQ Dry Run
    Gerrit에 CL을 업로드한 뒤 CQ Dry Run으로 빌드와 단위 테스트가 모두 통과(Passed)하는 것을 확인했습니다.

배운 점

1. 기술적 학습 (메모리 안전성과 모던 C++ 아키텍처)

  • base::span과 Fat Pointer 원리:
    • C++20 표준에 도입된 std::span 및 Chromium의 base::span은 시작 주소와 크기(size_t)를 함께 묶어 관리하는 경량 뷰(Fat Pointer / Bounded Pointer) 객체입니다.
    • 포인터만 넘길 때 놓치기 쉬운 버퍼 오버플로우(Buffer Overflow)를 경계 검사(Bounds Check)로 잡아낼 수 있습니다. Chromium과 Microsoft의 보안 분석에 따르면 심각도 높은 보안 취약점의 약 70%가 메모리 안전성 문제에서 비롯되는데 span 기반 인터페이스로의 전환(Spanification)이 이를 줄이기 위한 대표적인 노력임을 배웠습니다.
  • 연속 메모리(Contiguous Memory)와 복사 없는 뷰(Zero-Copy):
    • C++ 표준이 보장하는 연속 메모리 특성(vector는 C++03, string은 C++11부터) 덕분에 std::vector, std::string, C 배열, BoringSSL의 CryptoBuffer 등 서로 다른 컨테이너를 새 객체로 복사하지 않고 포인터와 크기만 담은 span 뷰(64비트 기준 16바이트)로 일관되게 전달할 수 있다는 점을 이해했습니다.
    • 데이터가 연속된 메모리에 놓이므로 공간 지역성(Spatial Locality)을 잘 살릴 수 있고 노드를 따라가는 포인터 체이싱(Pointer Chasing)에 비해 캐시 미스가 적습니다.
  • 스택 할당과 추가 비용 없는 전달:
    • span은 포인터와 크기만 가진 단순한 구조체여서 보통 스택이나 레지스터에 놓이고 생성과 소멸에 드는 비용이 사실상 없습니다(Zero-overhead).
    • span 자체는 힙을 할당하지 않기 때문에 데이터를 복사해 넘길 때 따라오는 할당 비용과 단편화(Fragmentation) 부담을 피할 수 있습니다.

2. 오픈소스 분석 및 문서 탐색 노하우

  • 설계 의도와 Git 커밋 로그 추적:
    • 트래킹 이슈(Issue 372283556)에 자세한 배경이 없을 때는 상위 이슈(Issue 374310081)와 crypto/hash.h최초 도입 커밋 로그를 따라가면 이 API가 왜 만들어졌는지(spanified, single-shot, 컴파일 타임 크기 검증) 설계 의도를 파악할 수 있다는 것을 배웠습니다.
  • file:docs 검색을 통한 공식 가이드 탐색:
    • Chromium Code Search에서 file:docs <키워드>(e.g. file:docs span)로 검색하면 공식 보안/가이드 문서(docs/unsafe_buffers.md)를 빠르게 찾을 수 있었습니다.

3. 코드 포맷팅 및 기여 프로세스

  • 코드 컨벤션 준수: Chromium에서는 git cl format으로 clang-format 기반 스타일 규칙(80자 줄 길이 제한, include 알파벳 정렬, 함수 인자 줄바꿈 등)을 맞춰 두어야 한다는 점을 배웠습니다. 이번 변경에서도 함수 이름이 길어지면서 줄바꿈 위치(auto hash = crypto::hash::Sha256(...))가 함께 조정되었습니다.
  • 프로세스 학습: GitHub 이슈 할당부터 브랜치 생성, 코드 마이그레이션, git cl format 적용, git cl upload를 통한 패치셋 업로드, LUCI CQ Dry Run 검증까지 Chromium 기여의 한 사이클을 경험했습니다.

참고 자료