# D 언어로 ASN.1 컴파일러를 1년간 개발한 기록

> Clean Markdown view of GeekNews topic #23895. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=23895](https://news.hada.io/topic?id=23895)
- GeekNews Markdown: [https://news.hada.io/topic/23895.md](https://news.hada.io/topic/23895.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-10-25T04:33:51+09:00
- Updated: 2025-10-25T04:33:51+09:00
- Original source: [bradley.chatha.dev](https://bradley.chatha.dev/blog/dlang-propaganda/asn1-compiler-in-d/)
- Points: 1
- Comments: 1

## Topic Body

- 한 개발자가 **D 언어로 ASN.1 컴파일러(dasn1)** 를 직접 구현하며 겪은 기술적·정신적 여정을 공유  
- 프로젝트는 **x.509 인증서와 TLS 1.3 구현**을 목표로 하며, ASN.1의 복잡한 **DER 인코딩 처리**를 지원  
- 글은 ASN.1의 구조적 난해함, **x.680~x.683 규격의 구현 난이도**, D 언어의 메타프로그래밍 활용법 등을 상세히 다룸  
- D의 **정적 import, mixin 템플릿, typeof(), alias this** 등 기능이 코드 생성과 AST/IR 설계에 어떻게 유용했는지 구체적으로 설명  
- 글은 “ASN.1은 고통스럽지만 배움이 큰 경험”이라며, **컴파일러 제작의 현실적 어려움과 보람**을 솔직하게 전함  

---

### 프로젝트 개요와 동기
- 저자는 **Juptune**이라는 D 기반 비동기 I/O 프레임워크를 개발 중이며, TLS 구현을 위해 ASN.1 DER 인코딩을 직접 처리할 필요가 있었음  
  - TLS의 x.509 인증서 구조를 파싱하려면 ASN.1의 복잡한 데이터 표현 방식을 이해해야 함  
- 이 프로젝트는 **학습과 재미**를 위한 개인적 도전으로 시작되었으며, 실제로 몇몇 인증서를 성공적으로 파싱하는 단계까지 진행  
- ASN.1은 1990년대의 오래된 표준이지만 여전히 **TLS, SNMP, LDAP 등 현대 시스템 전반에 사용**되고 있음  
- 저자는 “ASN.1은 세상에 널리 쓰이지만 대부분의 개발자는 존재조차 모른다”고 언급  

### ASN.1이란 무엇인가
- ASN.1(Abstract Syntax Notation One)은 **데이터 구조를 정의하고 인코딩하는 언어**, 일종의 “프로토버프의 조상”  
- 표준은 **표기법(x.680~x.683)** 과 **인코딩 규칙(BER, CER, DER, PER, XER, JER 등)** 으로 구성  
  - BER: 기본 TLV 형식, 무한 길이 지원  
  - CER: BER의 제한형, 항상 무한 길이 사용  
  - DER: BER의 결정적 하위집합, **암호화에 표준적으로 사용**  
  - PER/OER: 비트 단위 압축 인코딩  
  - XER/JER: XML·JSON 기반 인코딩  
- 인코딩 종류가 많아 복잡하지만, **유연성과 확장성**이 높음  

### ASN.1 표기법의 복잡성
- ASN.1의 기본 표준은 x.680이며, 확장 규격(x.681~x.683)은 **매우 난해한 학술적 문체**로 작성되어 있음  
- x.680만으로도 구현은 가능하지만, **의미 변환 규칙과 구문 변형**이 많아 구현 난도가 높음  
- x.681은 **Information Object Class 시스템**을 정의하며, 독자적인 초기화 문법을 지원  
  - 예: `CALLED &name [WHO IS &age YEARS OLD]`  
- x.682는 **Table Constraint**, x.683은 **템플릿형(Parameterized) 타입**을 정의  
  - D 언어의 제네릭과 유사한 개념으로, 타입과 값을 모두 매개변수로 받을 수 있음  

### ASN.1의 흥미로운 기능
- **제약(Constraint) 시스템**: 타입 정의 시 값의 범위나 크기를 직접 명시 가능  
  - 예: `UInt8 ::= INTEGER (0..255)`  
  - `SIZE`, `UNION(|)`, `INTERSECTION(^)` 연산자 지원  
- **버전 관리 시스템**: `OBJECT IDENTIFIER`를 통해 모듈 버전을 명확히 구분  
  - 예: `id-pkix1-implicit(19)` vs `id-mod-pkix1-implicit-02(59)`  
  - 이름 충돌 없이 명확한 모듈 식별 가능  

### D 언어가 코드 생성에 유리한 이유
- D의 **정적 import(static import)** 는 이름 충돌을 방지하며, ASN.1 타입 이름을 그대로 유지 가능  
- **모듈 로컬 조회(.Type1)** 기능으로 심볼 탐색을 명확히 제한  
- **typeof()** 로 타입을 자동 추론해 코드 생성 시 수동 관리 불필요  
- **후행 쉼표(trailing comma)** 허용으로 코드 생성 단순화  
- **컴파일 타임 상수 결합** 덕분에 `@nogc` 함수에서도 문자열 조합 가능  

### D 언어 기능을 활용한 구현 사례
#### Mixin 템플릿 기반 AST 노드
- D의 **mixin template** 기능을 이용해 ASN.1 구문 트리(AST) 노드를 정의  
  - 각 노드 타입(`List`, `Container`, `OneOf`)을 템플릿으로 재사용  
  - 복잡한 상속 대신 **컴파일 타임 코드 복사**로 단순화  

#### 템플릿 기반 API와 컴파일 타임 검증
- `Container` 노드는 여러 하위 노드를 포함하며, **컴파일 타임에 타입 검증** 수행  
  - `node.getNode!Asn1TagDefaultNode` 형태로 안전한 접근 가능  
- `OneOf` 노드는 여러 타입 중 하나를 저장하며, **`match` 함수로 패턴 매칭** 지원  
  - 모든 타입 핸들러를 반드시 정의해야 하므로 **컴파일 타임 안전성 확보**  

#### D의 메모리 관리 실험 패키지 활용
- `std.experimental.allocator`를 사용해 **@nogc 환경에서 객체 생성/해제** 구현  
  - `Region`, `StatsCollector` 등 조합으로 커스텀 할당자 구성  
  - 단, 10년째 실험적 상태로 유지 중  

#### alias this 기능
- `alias this`를 이용해 **래퍼 구조체가 내부 필드처럼 동작**하도록 구현  
  - 예: `cast(Asn1ValueReferenceIr)item` 형태로 간결한 캐스팅 가능  

#### version(unittest)
- `version(unittest)` 키워드로 **테스트 전용 함수**를 정의, 실제 빌드에는 포함되지 않음  

#### 템플릿 + with()를 이용한 테스트 하네스
- 공통 테스트 로직을 템플릿화하고, `with()` 문으로 **간결한 테스트 코드 작성**  
  - `Harness.T()` 대신 `T()`로 호출 가능  

### 구현 중 겪은 주요 어려움
#### 값 시퀀스 구문(Value Sequence Syntax)
- `{}`로 시작하는 여러 형태의 값 구문이 **문맥에 따라 모호**  
  - 파서 주석에 “이건 즐겁지 않다”는 표현이 있을 정도로 복잡  
- 구문 분석과 의미 분석을 분리했기 때문에 처리 난이도 상승  

#### 명세서의 불명확함
- 특정 조건에서 태그가 `EXPLICIT`로 처리되어야 하는 규칙 등, **문서에 명시되지 않은 동작** 존재  
- 모듈 버전 관리 방식도 명확히 정의되어 있지 않음  

#### 제약 조건의 3중 구현 필요
1. 구문 검사용  
2. 값 유효성 검사용  
3. 런타임 코드 생성용  
- UNION, INTERSECTION 처리 시 **에러 메시지 구성도 복잡**  

#### 불변 IR 노드의 환상
- AST를 IR로 변환한 뒤 수정이 필요 없을 것이라 생각했으나,  
  **`AUTOMATIC TAGS` 등 의미 변환 과정에서 데이터 변경 필요**  

#### ASN.1의 전면적 복잡성
- x.509는 구식 문법만 사용해 단순하지만, 최신 규격은 **x.681~x.683 구현이 필수**  
  - 이로 인해 ASN.1은 학술·상용 영역 외에는 거의 사용되지 않음  

#### ANY DEFINED BY 문제
- `ANY DEFINED BY`는 다른 필드 값에 따라 타입이 달라지는 구조  
  - dasn1은 이를 구현하지 않고, **커스텀 intrinsic `Dasn1-Any`** 로 대체  
  - 실제 디코딩 시 수동 처리 필요  

#### 정보 과부하
- ASN.1, x.68x, x.690, Juptune 등 여러 프로젝트 병행으로 **코드베이스 맥락 유지 어려움**  

### 컴파일러 제작의 현실
- 수천 개의 노드 방문자, 반복적 코드, 미세한 차이의 구현 등 **지루하고 고된 작업**  
- 그러나 각 단계마다 **큰 성취감과 학습 효과** 존재  
- “아무도 쓰지 않겠지만, 진짜 컴파일러 경험을 얻었다”고 회고  
- 마지막으로 “ASN.1은 하지 말라, 인생이 바뀐다”는 농담으로 글을 마무리  

### 결론
- 1년간의 작업에도 불구하고 dasn1은 아직 미완성이지만,  
  **D 언어의 잠재력과 ASN.1의 복잡성**을 깊이 이해하게 된 계기  
- 언젠가 “ASN.1 컴파일러 + TLS 1.3 구현 경험”을 이력서에 쓸 날을 꿈꾸며,  
  **개발자의 성장과 업계 현실**을 유머러스하게 되짚는 글로 마무리됨

## Comments



### Comment 45428

- Author: neo
- Created: 2025-10-25T04:33:53+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=45681200) 
- 요약하자면 ASN.1, D 언어, 그리고 컴파일러 자체에 대해 이야기하고 싶었음  
  하지만 일관된 형식을 찾지 못해 관련된 생각들을 모아 **블로그 글**로 묶었음  
  완성도는 높지 않지만, 짧게 다루기 어려운 주제라 양해 바람  
  - 교차 예시(intersection example)가 의도한 대로 동작하지 않는 것 같음  
    수학적으로 보면 `{0} ∪ ({2} ∩ {4,5,6,7,8}) = {0}`이므로 결과적으로 단일 값만 허용됨  
  - D 언어 이야기를 꺼내면 **Walter Bright**를 소환하는 셈임  
    개인적으로 D는 정말 좋아하지만, 현실적으로는 Go와 Rust가 훨씬 더 널리 쓰이고 있음  
  - 나도 ASN.1 데이터를 다뤄본 적이 있는데, 특히 **인증서** 관련 작업이 고통스러웠음  
    글쓴이의 고생에 깊이 공감함  
  - 글을 정말 재미있게 읽었음  
    D를 사랑하지만 오랫동안 손을 놓고 있었음  
    예전에 **파서와 프로토콜 구현**을 해본 경험이 있어 더욱 흥미로웠음  
  - 블로그는 결국 자신의 공간이니, 본인 방식대로 계속 이어가길 바람  

- “OMG ASN.1”이라니, 정말 반가운 주제임  
  인터넷이 성장하던 시절, **IETF**가 프로토콜을 발전시키던 때를 기억함  
  당시 기업들은 인터넷에 관심이 없었고, 학계와 IETF가 주도했음  
  하지만 기업들이 돈이 된다고 깨닫자 **[Protocol Wars](https://en.wikipedia.org/wiki/Protocol_Wars)** 가 시작됨  
  ASN.1은 그 전쟁의 산물이자 **기업 문화와 학문 문화의 충돌**을 보여주는 사례임  
  기업은 ‘레시피 문화’, 학계는 ‘기능 문화’로 비유할 수 있음  
  이 사고방식의 차이는 오늘날 **AI 개발 문화**에도 시사점을 줌  
  - 예전에 영화 *Father of the Bride*를 보다가 X.25 네트워킹 이야기가 나와서 깜짝 놀랐음  
    그때 인터넷이 아닌 “CN=wikipedia, OU=org, C=US” 같은 주소 체계로 갔을 수도 있다고 생각하니 아찔했음  
  - “OMG ASN.1”을 내 다음 밴드 이름으로 정해야겠다는 생각이 들었음  
  - 이야기의 일부는 맞지만, 주된 행위자를 ‘기업’으로 표현한 건 다소 부정확함  
    실제로는 **ITU와 ISO**가 중심이었음  
    이후 90년대 후반에는 또 다른 ‘프로토콜 전쟁’이 있었고, 이번엔 IETF가 졌음  
  - 이 전쟁은 인터넷의 **초기 상업화(en-shittification)** 과정이기도 했음  
    ISO는 완벽을 추구하다 느려졌고, IETF는 “나중에 고치자”는 태도로 빠르게 움직였음  
    그 결과 프로토콜이 굳어버리는 문제를 겪었음  
    또 1990년대 C용 ASN.1 구현이 형편없었던 것도 문제였음  
  - 기업 관점이란 결국 **메인프레임 관점**이었다는 점이 핵심임  

- 터키 속담에 “이건 사람이 쓸 물건이 아님!”이라는 표현이 있음  
  이 말을 **디자인 철학의 모토**로 삼고 싶음  
  또한 “판결을 내린 자가 직접 칼을 휘둘러야 한다”는 *Game of Thrones*의 대사처럼,  
  **스펙을 만든 사람은 직접 파서를 구현해야 함**  
  실제 작동하는 파서와 테스트가 함께 제출되어야 스펙이 승인되는 식으로 바뀌면 품질이 훨씬 좋아질 것 같음  

- D 언어를 정말 좋아함  
  Raylib만 의존해 **vim 스타일 텍스트 에디터**를 직접 구현 중임  
  D의 장점은 다음과 같음  
  * 어디서든 **unit test**를 작성할 수 있음  
  * `version(unittest)` 블록으로 테스트 전용 코드 관리가 쉬움  
  * enum, union, assert, 계약 프로그래밍 등 언어적 지원이 훌륭함  
  문서를 참고하거나 ChatGPT에 물어보면 항상 우아한 해결책을 찾을 수 있었음  
  - D는 나에게 **달콤쌉싸름한 언어**임  
    설계 철학적으로 완벽에 가깝지만, 도구와 생태계가 Rust나 Go 수준이었다면 훨씬 성공했을 것임  
  - D의 기능은 좋지만 점점 **언어가 시끄러워지는(noisy)** 경향이 있음  
    Phobos 표준 라이브러리는 작은 불편이 너무 많아 결국 포기했음  
    새 버전인 Phobos V3가 진행 중이지만 인력이 적어 기대 반, 걱정 반임  

- “ASN.1이 복잡하다고 말한 적 있던가?”  
  스키마와 데이터 포맷 모두 복잡하지만, 대부분은 무시 가능한 복잡성임  
  나는 ASN.1 스키마 표기법을 쓰지 않고, 직접 **DER 구현체**를 C로 작성했음  
  DER은 표준 인코딩 중 유일하게 쓸 만하다고 생각함  
  또한 DSER, SDSER, TER 같은 **자체 인코딩 포맷**도 만들었음  
  `ANY DEFINED BY` 같은 구조도 여전히 유용하게 사용 중이며,  
  효율적인 인코딩을 위해 **OBJECT IDENTIFIER RELATIVE TO**라는 비표준 기능도 추가했음  

- 나도 ASN.1 컴파일러를 만들어본 경험이 있음  
  X.681~X.683의 일부 기능만 구현했지만, 한 번의 **코덱 호출로 전체 인증서**를 재귀적으로 디코딩할 수 있게 했음  
  ASN.1은 단순한 문법이 아니라 **강력한 타입 시스템**임  
  과소평가받지만 정말 멋진 기술임  

- 예전에 Swift용 ASN.1 컴파일러를 만든 적이 있음  
  [ASN1Codable](https://github.com/PADL/ASN1Codable) 프로젝트로, Heimdal의 [libasn1](https://github.com/heimdal/heimdal/tree/master/lib/asn1)을 활용해  
  ASN.1을 **JSON AST**로 변환해 파싱을 단순화했음  
  - libasn1의 README에는 ASN.1에 대한 **은근한 혐오감**이 느껴짐  
    “JSON으로 바꾸자”는 말은 결국 상처받은 개발자의 외침 같음 😄  

- 이상하게도 ASN.1 작업이 **즐겁게 느껴짐**  
  언젠가 Rust용 ASN.1 컴파일러를 직접 만들어보고 싶음  
  현재 Rust 구현체들은 대부분 derive 매크로나 수동 체이닝 방식이라 아쉬움  

- 일반적으로 표준을 구현할 때는 80% 기능을 20% 시간에 완성하지만,  
  ASN.1의 나머지 20%는 **평생이 걸릴 수도 있음**  

- 예전에 Netscape 코드베이스의 ASN.1 파서를 확장해 **PKCS#12**를 지원했음  
  RSA 표준과 ASN.1 정의를 너무 깊이 알게 되어 후회했지만,  
  블로그 작성자의 **끈기와 약간의 마조히즘**에는 존경을 보냄  
  - 그 경험이라면 정말 **전쟁 같은 개발 일화**가 많을 것 같음
