CWT기술이 적용된 EU의 COVID-19 백신접종 증명서(EUDCC)

김재우·2021년 7월 13일
1
post-thumbnail

2021년 7월 1일 EU에서는 코로나19 백신 디지털증명서(EU Digital COVID Certificate, EUDCC) 운용을 정식으로 시작했다고 발표했습니다. 이 EUDCC는 기술적으로 재미이는 부분이 있어 이에 대해서 이야기해봅니다. 예로, Base45(비트코인이 Base58을 사용중임)라는 새로운 인코딩 방식을 도입하고 있고 포멧으로 CWT(CBOR Web Token)을 채용하고 있습니다. CWT는 최근 보급되고 있는 JWT의 바이너리 버전이라고 봐도 좋고 비교적 최근 규격입니다. 최근 필자도 관심을 가지고 CWT에 관심이 있어 테스트를 해보고 있는 가운데 EUDCC 규격에 적용되었다는 소식을 접하고 나름데로 테스트해본 코드를 정리해보고자 합니다.

시작하기

EUDCC(EU Digital COVID Certificate는 유럽위원회와 EU회원국이 정의한 코로나19 백신접종에 대한 일반적인 인증서입니다. 디지털과 종이 모두 처리할 수 있도록 설계되어 있으며, QR코드에 들어가는 정보표현으로 CWT(CBOR Web Token)이 채용되고 있습니다. CWT를 좀더 쉽게 이야기하자면, JWT(JSON Web Token)의 바이너리 버전으로 JWT이 비해 컴팩트하게 인코딩되며, JWT계열 보안 문제도 해결된 것이 장점입니다.

다음은 EUDCC의 개요 및 기술스펙, 테스트 데이터로 검증코드의 구현과 평가를 해보려고 합니다. 참고로 CWT에 포멧된 EUDCC 자체 검증 코드는 Python CWT에서 아래와 같이 간단하게 작성됩니다. 검증 키로드(1)과 검증 및 디코딩(2) 설정 2줄으로 끝납니다.

import cwt
from cwt import Claims, load_pem_hcert_dsc

# EUDCC 발행자 인증서 (검증용 공개키)
# A DSC(Document Signing Certificate) issued by a CSCA (Certificate Signing Certificate Authority) quoted from: https://github.com/eu-digital-green-certificates/dgc-testdata/blob/main/AT/2DCode/raw/1.json
dsc = "-----BEGIN CERTIFICATE-----\nMIIBvTCCOWOgAwIBAgIKAXk8i88OleLsuTAKBggqhkjOPQQDAjA2MRYwFAYDVQQDDA1BVCBER0MgQ1NDQSAxMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMB4XDTIxMDUwNTEyNDEwNloXDTIzMDUwNTEyNDEwNlowPTERMA8GA1UEAwwIQVQgRFNDIDExCzAJBgNVBAYTAkFUMQ8wDQYDVQQKDAZCTVNHUEsxCjAIBgNVBAUTATEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASt1Vz1rRuW1HqObUE9MDe7RzIk1gq4XW5GTyHuHTj5cFEn2Rge37+hINfCZZcozpwQKdyaporPUP1TE7UWl0F3o1IwUDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFO49y1ISb6cvXshLcp8UUp9VoGLQMB8GA1UdIwQYMBaAFP7JKEOflGEvef2iMdtopsetwGGeMAoGCCqGSM49BAMCA0gAMEUCIQDG2opotWG8tJXN84ZZqT6wUBz9KF8D+z9NukYvnUEQ3QIgdBLFSTSiDt0UJaDF6St2bkUQuVHW6fQbONd731/M4nc=\n-----END CERTIFICATE-----"

# 검증대상 EUDCC
# An EUDCC (EU Digital COVID Certificate) quoted from: https://github.com/eu-digital-green-certificates/dgc-testdata/blob/main/AT/2DCode/raw/1.json
eudcc = bytes.fromhex("d2844da20448d919375fc1e7b6b20126a0590133a4041a61817ca0061a60942ea001624154390103a101a4617681aa62646e01626d616d4f52472d3130303033303231356276706a313131393334393030376264746a323032312d30322d313862636f624154626369783155524e3a555643493a30313a41543a31303830373834334639344145453045453530393346424332353442443831332342626d706c45552f312f32302f31353238626973781b4d696e6973747279206f66204865616c74682c20417573747269616273640262746769383430353339303036636e616da463666e74754d5553544552465241553c474f455353494e47455262666e754d7573746572667261752d47c3b6c39f696e67657263676e74684741425249454c4562676e684761627269656c656376657265312e302e3063646f626a313939382d30322d323658405812fce67cb84c3911d78e3f61f890d0c80eb9675806aebed66aa2d0d0c91d1fc98d7bcb80bf00e181806a9502e11b071325901bd0d2c1b6438747b8cc50f521")

# 1. EUDCC 발급자의 인증서를 검증용 공개키로 읽음
public_key = load_pem_hcert_dsc(dsc)

# 2. 검증 및 디코딩
decoded = cwt.decode(eudcc, keys=[public_key])

# 3. EUCC 내용(페이로드)의 취득 및 페이로그 부분은 아래와 같음 
claims = Claims.new(decoded)
# claims.hcert[1] == decoded[-260][1] ==
# {
#     'v': [
#         {
#             'dn': 1,
#             'ma': 'ORG-100030215',
#             'vp': '1119349007',
#             'dt': '2021-02-18',
#             'co': 'AT',
#             'ci': 'URN:UVCI:01:AT:10807843F94AEE0EE5093FBC254BD813#B',
#             'mp': 'EU/1/20/1528',
#             'is': 'Ministry of Health, Austria',
#             'sd': 2,
#             'tg': '840539006',
#         }
#     ],
#     'nam': {
#         'fnt': 'MUSTERFRAU<GOESSINGER',
#         'fn': 'Musterfrau-Gößinger',
#         'gnt': 'GABRIELE',
#         'gn': 'Gabriele',
#     },
#     'ver': '1.0.0',
#     'dob': '1998-02-26',
# }

EU Digital COVID Certificate란?

EUDCC는 유럽위원회와 EU회원국이 정의한 COVID-19의 백신접종증명서이며 정확하게는 "백신 접종 후(Vaccination Certificate)", "감염후 회복(Recovert Certificate), "검사결과 음성(Certificate for Test Results)"라는 3가지 인증서를 합쳐서 EUDCC라고 부릅니다. 또는 EU Digital Green Certificate(DGC)라고 하기도 합니다. EU국가 내에서의 안전한 이동을 실현하는 것을 목적으로 하고 있으며, EU회원국 간의 상호 운용성 및 부정위조 방지를 위한 보안이 필수 요건입니다. 당연히 개인정보도 고려되어 있고, 개인정보가 다른 국가로 제공될 수 없도록 설계되었습니다.


EUDCC는 디지털과 종이로 취급할 수 있는 QR코드로 사용할 수 있는 요건으로 하고 있어, 이를 위해 컴팩트한 인코딩방식을 채용하고 있습니다. 상세 내용은 나중에 설명하겠지만, 개인이 백신접종을 했는지를 나타내는 최소한의 정보를 증명서에 기재되어 이를 신뢰할 수 있는 기관의 전자서명이 부여되도록 하고 있습니다. 이 전자서명 검증키는 검증 애플리케이션용으로 공개되며, 이를 사용하여 정상적인 인증서임을 확인할 수 있습니다. 이런 형식과 트러스트 프레임워크등의 기술사양은 eHealth Network를 통해 발행되고 공개하고 있습니다.참고용 레퍼런스 구현 및 테스트 데이터는 GitHub에 오픈소스로 공개되어 있습니다.

기술 스펙

EUDCC 관련 기술사양은 여러 문서를 통해 구성되어 있습니다. 인증서 형식에 그치지 않고 EU회원국간에 걸친 검증을 실현하기 위한 게이트웨이(DGCG) 사양과 DGCG와 같이 각국가별 백엔드서버가 가지는 기능 사양을 위한 발행 및 검증을 위한 애플리케이션 사양까지 포함됩니다.

이 글에서는 전체 구성을 살펴본 후, 다양한 기술내용중에서 CWT관련 기술사양에 중점을 둡니다.

스펙 목록

EUDCC 관련 기술스펙에서 중요한 것은 eHealth Network가 "Technical Specifications for Digital Green Certificates"로 책정하고 공개하고 있습니다. 각각 개요는 아래와 같습니다.

  • Volume 1 (Electronic Health Certificate Specification)
    - 기본 스펙이며, EUDCC 범용 데이터구조 및 트러스트 프레임워크를 정의하고 있습니다. 종이와 디지털매체에 QR코드를 사용하는 인코딩방법을 규정하고 있습니다. 이 문서의 최신 버전은 Electronic Health Certificate Specification에서 GitHub프로젝트에서 관리합니다.
  • Volume 2 (European Digital Green Certificate Gateway)
    - EU회원국을 간 EUDCC 상호 검증을 위한 트러스 프레임워크를 지원하는 DGCG 아키텍쳐, 기술스펙을 규정하고 있습니다. 위 개요도를 보면, 어떤 Pub/Sub기반을 이미징하지만, 실체는 EUDCC확인용 인증서(DSC: Document Signing Certificate) 및 해당 CA인증서 레지스트리이며, CRUD용 REST API 서버입니다. API사양은 최근 Open API Spec에서 Digital Green Certificate Gateway로 구현되어 GitHub로 공개되어 있습니다.
  • Volume 3 (Interoperable 2D Code)
    - Volume 1에서 기재되어 있는 EUDCC범용 데이터 구조 및 인코딩방법을 구체적으로 규정한 것입니다. 이 글에서 주로 다루는 내용입니다. Volume 1과 중복되는 내용이 많지만, 총돌되는 경우 Volume 1이 우선시 됩니다.
  • Volume 4 (European Digital Green Certificate Applications)
    - EU전체에 EUDCC 검증에 필요한 게시자 앱 지갑 애플리케이션, 검증 애플리케이션 가맹국의 백엔드 서비스 핵심 기능에 대해 설명하고 있습니다. iOS, Android 모바일앱 레퍼런스도 GitHub에 공개되어 있습니다.
  • Volume 5 (Public Key Certificate Governance)
    - DGCG 및 이를 이용하는 EU각 국가별 백엔드 서비스 사이에서는 여러 유형의 인증서가 이용되지만 이 PKI지배구조에 대해 규정하고 있습니다. 구체적으로 각 인증서 템플릿의 유효기간 해지를 포함한 라이프사이클 관리에 대해 상세히 설명하고 있습니다. 이것도 GitHub에서 관리되고 있습니다.

위 5가지의 사양이 완료된 것은 아닙니다. 위 목록에서 설명하고 있는 API스펙도 그렇지만, 그외에도 중요한 문서지침사양이 있습니다. 몇가지를 설펴보면 아래와 같습니다.

이제 CWT관련해서 Volume3를 중심으로 진행합니다. 참고로 DGCG 포함 PKI 관련 내용도 재미있기 때문에 관심이 있는 분들은 Volume 2, 5내용을 참고하시면 좋을듯 싶스빈다.

데이터 구조 형식

EUDCC는 2차원코드(QR코드)의 풋프린트를 최소화하기 위해 인코딩하고 CBOR(Concise Binary Object Representation)을 데이터무결성을 보장하기 위해 COSE(CBOR Object Signature and Encryption)을 채용하고 있습니다. 이 COSE 및 CBOR을 기반으로 EUDCC을 표현하는 방법이 CWT(CBOR Web Token)입니다.

참고로 CBOR은 JSON바이너리 버전인 것으로 가독성은 없지만, 데이터를 컴팩트하게 표현할 수 있습니다. 현재는 작은 규역이지만 WebAuthn에서 아테스테이션 정보의 인코딩방식으로 채용되고 있었기 때문에 웹관련 프로젝트에서 인지도가 높아지고 있습니다. COSE는 JSON에서 JOSE(JSON Object Signing and Encryption)의 CBOR버전입니다. 또한 JOSE의 보안문제를 해결하고 컴팩트한 장점이 있습니다.

COSE헤더

CWT 클레임을 페이로드로 전송하는 COSE헤더에는 아래 두가지를 지정합니다. 모두 서명으로 보호되는 영역(Protected Header)에 지정합니다.

  • alg: 서명알고리즘, JWT에서도 익숙한 ES256과 PS256 두가지가 가능합니다. 전자가 기본 알고리즘 후자가 보조 알고리즘으로 지정되어 있습니다. 보조 알고리즘은 기본 알고리즘이 규제등으로 사용할 수 없는 경우에만 사용됩니다.
  • kid: EUDCC 서명에 사용된 공개키(DSC: Document Signing Certificate)를 식별하는 ID입니다. kid는 본래 보호할 필요가 없고, Unprotected Header에 지정하는 것이 일반적이지만, EUDCC는 Protected Header에 지정합니다. 또한, kid는 EUDCC사양의 규정으로써 DSC의 SHA256 해시값 선두 8byte를 이용합니다. 충돌 가능성이 있기 때문에 검증 애플리케이션은 EUDCC에 포함된 kid에서 모든 DSC를 체크해야 합니다.

CWT 클레임

다음 COSE에서 운반되는 페이로드(CWT 클레임)에 대해 CWT사양(RFC8392)은 클레임 기본정보(인증서 발급자 및 유효기간등의 기본정보)를 정의하고 있지만 필수항목은 정하고 있지 않습니다."어떤 항목을 사용하는등" 운용은 사용하는측에 맡겨져 있습니다. Volume 3는 다음 4가지 항목을 공통 데이터셋으로 규정하고 있습니다.

  • iss: 발행자 정보, ISO 3166-1 alpha-2 국가코드(DE등)이 들어갑니다.
  • iat: 발행일, DSC의 유효기간 이전에 설정해야 합니다.
  • exp: 만료일, DSC의 유효기간 초과를 할 수 없습니다.
  • hcert: 예방 접종 증명서등 증명서 유형별 페이로드 정보입니다. 이 hcert는 Electronic Health Certificate Specification(=Volume1)에 정의된 그 자체는 EUDCC이외의 건강 증명서에 사용할 수 있는 범용적인 것입니다. EUDCC의 경우 키1(EUDCC임을 나타내는)가 지정된 값에 위 Technical Specifications for EUDCCs - JSON Scheme Specification에 정의된 JSON데이터가 설정됩니다.

전송 인코딩

위 CWT를 그대로 Raw데이터로 전송해도 좋지만, QR코드로 표현하는 경우에는 더 컴팩트하게 처리하도록 요구하고 있습니다.구체적으로는 아래에 있는데로 CWT를 만든 후에 다음 두가지 작업을 수행합니다.

  • ZLIB 압축
  • Base54 인코딩

    Base54인코딩은 EUDCC를 위해 개발된 인코딩 방식으로 IETF에 The Base45 Data Encoding으로 제안되고 있습니다. (2021년 7월 12일 기준으로 초안 상태임) QR코드는 바이너리 모드에서 데이터를 UTF-8문자열로 처리하려고 하는 모든 바이트를 직접 인코딩할 수 없고, 일단 Base64등 인코딩하여 QR코드화하는 것이 일반적입니다. Base45는 Base64/32/16(RFC4648)에 비해 보다 컴팩트한 QR코드를 만드는 것입니다.

검증방법

EUDCC가 정식기관에서 발급한 유효한 인증서임을 확인하는 방법은 기본적으로 COSE사양에 따릅니다. EUDCC 특유 체크포인트로 위의 exp, iat값 및 DSC 유효기간의 어긋남을 확인하고 hcert검증이 있지만 그외에는 COSE검증단계에 남아 있습니다.

문제는 검증에 필요한 EUDCC발급자 인증서(DSC: Document Signing Certificate)를 어떻게 얻는지이지만, DSC목록 제공방법은 EU회원국에 맡겨져 있습니다. Volume1에는 일례로 JWT에 익숙한 JWK set format(RFC7517 section5)에 서명하는 경우를 들 수 있습니다. 스웨덴이 이 방식을 채용하고 있으면 Document Signer Certificate(DSC) Trust List - Format Specification로 사양을 공개하고 있습니다. (공개 엔드포인트URL을 포함하여 여기에 정보가 정리되어 있음)

한편, GitHub에 공개된 검증애플리케이션의 레퍼런스 구현은 Volume4에서 정의되는 Verifier API를 이용하여 EU회원국의 백엔드 서비스(아래 dgca-verifier-service)에서 DSC목록을 얻을 구조로 되어 있으며, 이것이 사실상 표준이라고 할 수 있을 것 같습니다. (각 나라별 검증 애플리케이션 구현 실태까지 확인하기 어려움) 이 Verifier API는 Digital Green Certificate Verifier Service로 웹API정의가 공개되어 있습니다.

예를 들어, 이 Verifier API를 사용하는 경우, EUDCC의 검증은 다음과 같이 실행하면 좋습니다.

  1. 검증 애플리케이션은 정기적으로 (예로 1일 1회) Verifier API를 호출 DSC목록을 업데이트합니다.
  • GET/signercertificateUpdate 업데이트가 없어질 때까지 반복호출 DSC목록을 업데이트합니다.
  1. 검증시 검증 애플리케이션은 검증 대상 EUDCC의 kid이 GET/signercertificateStatus결과와 비교하여 유효한지 확인합니다.
  • GET/signerceriticateStatus를 검증할 때마다 호출하거나 애매합니다. 적어도 한단계보다 높은 빈도로 호출이 기대된 방법으로 보입니다.
  1. 검증 애플리케이션은 KID에 해당하는 DSC를 읽고 이를 검증키로 EUDCC 서명검증을 실시합니다. 이때, DSC의 유효기간과 iss와 exp 상충이 없는지 확인합니다.

이상 CWT주위 포멧 및 확인방법에 중점을 두고 EUDCC를 지원하는 기술에 대해 정리해 보았습니다.

검증코드 구현

EUDCC관련 시스템 구성요소별로 오픈소스로 공개되어 있습니다. 보통 CWT/COSE라이브러리 Python CWT를 사용하여 관련 검증코드를 작성해 보았습니다.
우선 Verifier API에서 EUDCC 검증을 위한 공개키(DSC)를 얻는 과정은 아래와 같습니다. 중요한 부분은 load_pem_hcert_dsc)를 호출 PEM형식의 DSC를 EUDCC검증에 그대로 사용할 COSE key객체로 변환해서 목록화(self._dscs)하고 있는 부분입니다.

rom cwt import load_pem_hcert_dsc

# 생략

def refresh_trustlist(self):
    status = 200
    headers = None

    # Get new DSCs
    x_resume_token = (
        self._trustlist[len(self._trustlist) - 1]["x_resume_token"]
        if self._trustlist
        else ""
    )
    while status == 200:
        if x_resume_token:
            headers = {"X-RESUME-TOKEN": x_resume_token}
        r = requests.get(
            self._base_url + "/signercertificateUpdate", headers=headers
        )
        status = r.status_code
        if status == 204:
            break
        if status != 200:
            raise Exception(f"Received {status} from signercertificateUpdate")

        x_resume_token = r.headers["X-RESUME-TOKEN"]
        self._trustlist.append(
            {
                "x_kid": r.headers["X-KID"],
                "x_resume_token": x_resume_token,
                "dsc": r.text,
            }
        )

    # Filter expired/revoked DSCs
    r = requests.get(self._base_url + "/signercertificateStatus")
    if r.status_code != 200:
        raise Exception(f"Received {r.status_code} from signercertificateStatus")
    active_kids = r.json()
    self._dscs = []
    for v in self._trustlist:
        if v["x_kid"] not in active_kids:
            continue
        dsc = f"-----BEGIN CERTIFICATE-----\n{v['dsc']}\n-----END CERTIFICATE-----"
        self._dscs.append(load_pem_hcert_dsc(dsc))

    # Update trustlist store.
    with open(self._trustlist_store_path, "w") as f:
        json.dump(
            [v for v in self._trustlist if v["x_kid"] in active_kids], f, indent=4
        )
    return

다음 메인의 검증작업입니다. HC1:가 붙어 있는 경우 QR코드를 위한 ZLIB압축/Base54인코등이 이루어지고 있는 것으로 보여 해당 압축 디코딩 처리를 하고 있습니다. CWT 검증 자체가 마지막 cwt.decode()에 열립니다. 검증대상 EUDCC와 위 refresh_trustlist()에서 만든 COSE key목록(self._dscs)전달하는 것입니다. 내부에서 kid데이터를 포함한 검증이 실행됩니다.

import cwt

# 생략

def verify_and_decode(self, eudcc: bytes) -> bytes:
    if eudcc.startswith(b"HC1:"):
        # Decode Base45 data.
        eudcc = b45decode(eudcc[4:])
        # Decompress with zlib.
        eudcc = zlib.decompress(eudcc)
    # Verify and decode CWT.
    return cwt.decode(eudcc, keys=self._dscs)

마지막으로 위 두 함수를 포함하는 샘플 Verifier클래스를 사용한 일련 검증작업을 붙여둡니다.

 An endpoint of Digital Green Certificate Verifier Service compliant with:
# https://eu-digital-green-certificates.github.io/dgca-verifier-service/
BASE_URL = os.environ["CWT_SAMPLES_EUDCC_BASE_URL"]
# e.g., "./dscs.json"
TRUSTLIST_STORE_PATH = os.environ["CWT_SAMPLES_EUDCC_TRUSTLIST_STORE_PATH"]
# quoted from https://github.com/eu-digital-green-certificates/dgc-testdata/blob/main/AT/2DCode/raw/1.json
BASE45_FORMATTED_EUDCC = b"HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH-R6IOOK.IR9B+9G4G50PHZF0AT4V22F/8X*G3M9JUPY0BX/KR96R/S09T./0LWTKD33236J3TA3M*4VV2 73-E3GG396B-43O058YIB73A*G3W19UEBY5:PI0EGSP4*2DN43U*0CEBQ/GXQFY73CIBC:G 7376BXBJBAJ UNFMJCRN0H3PQN*E33H3OA70M3FMJIJN523.K5QZ4A+2XEN QT QTHC31M3+E32R44$28A9H0D3ZCL4JMYAZ+S-A5$XKX6T2YC 35H/ITX8GL2-LH/CJTK96L6SR9MU9RFGJA6Q3QR$P2OIC0JVLA8J3ET3:H3A+2+33U SAAUOT3TPTO4UBZIC0JKQTL*QDKBO.AI9BVYTOCFOPS4IJCOT0$89NT2V457U8+9W2KQ-7LF9-DF07U$B97JJ1D7WKP/HLIJL8JF8JFHJP7NVDEBU1J*Z222E.GJ457661CFFTWM-8P2IUE7K*SSW613:9/:TT5IYQBTBU16R4I1A/9VRPJ-TS.7ZEM7MSVOCD4RG2L-TQJROXL2J:52J7F0Q10SMAP3CG3KHF0DWIH"
# RAW_EUDCC = bytes.fromhex("d2844da20448d919375fc1e7b6b20126a0590133a4041a61817ca0061a60942ea001624154390103a101a4617681aa62646e01626d616d4f52472d3130303033303231356276706a313131393334393030376264746a323032312d30322d313862636f624154626369783155524e3a555643493a30313a41543a31303830373834334639344145453045453530393346424332353442443831332342626d706c45552f312f32302f31353238626973781b4d696e6973747279206f66204865616c74682c20417573747269616273640262746769383430353339303036636e616da463666e74754d5553544552465241553c474f455353494e47455262666e754d7573746572667261752d47c3b6c39f696e67657263676e74684741425249454c4562676e684761627269656c656376657265312e302e3063646f626a313939382d30322d323658405812fce67cb84c3911d78e3f61f890d0c80eb9675806aebed66aa2d0d0c91d1fc98d7bcb80bf00e181806a9502e11b071325901bd0d2c1b6438747b8cc50f521")

if __name__ == "__main__":
    v = Verifier.new(BASE_URL, TRUSTLIST_STORE_PATH)
    v.refresh_trustlist()
    try:
        res = v.verify_and_decode(BASE45_FORMATTED_EUDCC)  # or RAW_EUDCC
    except Exception as err:
        print("Verification failed: %s" % err)
        exit(1)
    hcert = res[-260][1]
    print(hcert)
# {
#     'v': [
#         {
#             'dn': 1,
#             'ma': 'ORG-100030215',
#             'vp': '1119349007',
#             'dt': '2021-02-18',
#             'co': 'AT',
#             'ci': 'URN:UVCI:01:AT:10807843F94AEE0EE5093FBC254BD813#B',
#             'mp': 'EU/1/20/1528',
#             'is': 'Ministry of Health, Austria',
#             'sd': 2,
#             'tg': '840539006',
#         }
#     ],
#     'nam': {
#         'fnt': 'MUSTERFRAU<GOESSINGER',
#         'fn': 'Musterfrau-Gößinger',
#         'gnt': 'GABRIELE',
#         'gn': 'Gabriele',
#     },
#     'ver': '1.0.0',
#     'dob': '1998-02-26',
# }    
    exit(0)

사용해본 소감

EUDCC관련 스펙

CWT를 이용하는 규격으로 더 엄격하게 운용규격을 결정ㅇ해서 좋았단 것으로 생각됩니다. 예로 iss, exp, iat, hcert클레임읋 사용하고 있지만 CWT의 구조도 COSE_Sign1으로 구성하면 좋은데 COSE_SIgn도 은근히 허용되고 느슨한 느낌의 EU연합의 정책을 이해하기 어렵지만, 유럽국가 수중에서 상호운용성이 엄격하게 보장되지 않는다라는 생각이 들었습니다.

Verifier API 사양은 원래 kid 중복이 있다는 전제로 /signercertificateStatus는 엄격하게 kid유효성 검증에 사용할 수 없는 것이기 때문에 /signercertificateUpdate에서 모든 유효한 DSC를 얻을수밖에 없습니다. 이 경우, DSC를 하나씩 얻어야 하기 떄문에 상당히 비효율적으로 보입니다. 공개된 코드로 엔드포인트에서 테스트를 해보니 refesh_trustlist를 통해 DSC를 얻는데 2-3분이상 걸렸습니다.

또한 EUDCC의 개방형 자산(주요 라이선스가 Apache 2.0)이기 떄문에 이를 활용하면 상당히 저렴한 개발비용으로 코로나19 백신증명여권을 만들 수 있을 것 같습니다. (다만 성능은 보장 못함 ㅠ_ㅠ)

참고로 EUDCC의 기술스펙 제작사로 이름으로 eHealth Network는 이 EU연합 조직에서 중요한 역할이라고 보여집니다. eHealth 보급과 EU회원국간 협력을 촉진시키기 위한 목적으로 유렵위원회 건강, 식품 안전청이 설치되어 있는 네트워크로 디지털 헬스케어를 관할하는 모든 EU국가가 자발적으로 모여있어 각 유럽국가의 디지털 헬스 시스템간 상호호운용성 문제흘 해결하고 있는 역할 단체로 보입니다.

참고

EUDCC 관련 GitHub Organization

이들 저장소는 2021년 3월에 작성되었고 공개전까지는 개발이 오래되었는지는 알 수 없지만, 적어도 GitHub에서 2021년 3월말 이후 4월까지 저장소가 만들어지고 빠르게 개발이 이루어진것으로 추측됩니다. EU소식을 찾기 어려운 지라 유럽에서 코로나19 감염자 및 접촉자 감지 애플리케이션을 위한 EU Federation Gateway Service가 작년 여름에 정비되었고 EU각 나라별 백엔드 서비스와 같이 실행구조는 EUDCC의 DGCG와 비슷합니다. 그리고 접촉자 감지 시스템 리소스가 어느정도 활용되고 있어 보입니다.

기본 뼈대가 되는 시스템 설계, 개발, 구축(운용)을 할 수 있는 기업을 바탕에 두고, 제품을 서서히 오픈소스화하여 개발자들의 협력을 얻는 스타일은 현재 한국내 개발자들에게 도움이 되는 모범사례라고 생각됩니다.

by Jason Jaewoo, Kim

profile
Software Developer & Writer, Speaker

0개의 댓글