레이블이 리뷰인 게시물을 표시합니다. 모든 게시물 표시
레이블이 리뷰인 게시물을 표시합니다. 모든 게시물 표시

2018년 12월 26일 수요일

Bouncy Castle ASN.1 TestCase Reivew

전체적인 소스의 구성을 파악하기 위하여 모든 소스를 리뷰하는 방식보다는 프로그램의 주요 테스트를 하는 TestCase를 살펴보는 것이 빠른 소스 리뷰에 도움이 됩니다.
각 테스트 케이스를 살펴보고 , 거기 사용된 Class를 Reivew 하도록 하겠습니다.
리뷰의 순서는 TestCase기준으로 알파벳 순으로 정리하였습니다. 알파벳 순으로 정리되었기 때문에 원시 클래스에 가까운 부분의 테스트가 더 이후에 나올 수 있습니다.

BouncyCastle ASN.1 Test케이스의 공통점.

기본적으로 SimpleTest 혹은 Asn1UnitTest 라는 클래스에서 상속 받아 처리하도록 하였으며,
대부분의 경우 해당 TestClass에서 PerformTest() 함수 안에 필요한 실제 테스트의 내용이 들어있습니다.
이후에는 해당 TestClass명을 언급하고 PerformTest()의 내용을 설명하면서 진행하도록 하겠습니다.코드가 중복되거나 같은 영역에 대한 테스트는 삭제합니다.

AdditionalInformationSyntaxTest





사용된 Class는 다음과 같습니다.
AdditionalInformationSyntax
그림에서 보는 바와 같이 기본 클래스인 Asn1Encodeable을 상속 받고 있습니다. 즉 ASN1문자열로 반환이 가능하다는 의미입니다.
DirectoryString
ASN.1 정의에 따르면 DirctoryString은 아래와 같으며 해당 부분을 실제로 구현한 것입니다.
DirectoryString ::= CHOICE {
teletexString TeletexString (SIZE (1..MAX)),
printableString PrintableString (SIZE (1..MAX)),
universalString UniversalString (SIZE (1..MAX)),
utf8String UTF8String (SIZE (1..MAX)),
bmpString BMPString (SIZE (1..MAX))
}
다시 정리하면 DirectoryString은 출력가능한 위의 정의된 Type중의 하나여야 한다는 의미입니다.


테스트 코드의 내용 정리


생성시에는 반드시 허용되는 문자열 형식중의 하나가 인자로 전달되어야 하며, 해당인자가 충족하지 않는( new Object()로 생성된 ) 경우는 에러가 발생해야 합니다. 실제로 이 부분은 Spec(X.500)에서 정의된 것과 일치합니다. 인증서 부가 정보에 대한 내용은 X.509에 해당합니다.

AdmissionSyntaxUnitTest

인증서의 규약 자체가 ASN.1으로 서술된 경우가 많습니다.


AdmissionSyntax
ASN.1으로 AdmissionSyntax를 정의하면, 다음과 같습니다. 인증에 관련된 속성을 정의 합니다.
→ Bouncy Castle 문서 빌드에서 참고.
     AdmissionSyntax ::= SEQUENCE
     {
       admissionAuthority GeneralName OPTIONAL,
       contentsOfAdmissions SEQUENCE OF Admissions
     }
 

     Admissions ::= SEQUENCE
     {
       admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
       namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
       professionInfos SEQUENCE OF ProfessionInfo
     }
 

     NamingAuthority ::= SEQUENCE
     {
       namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
       namingAuthorityUrl IA5String OPTIONAL,
       namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
     }
 

     ProfessionInfo ::= SEQUENCE
     {
       namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
       professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
       professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
       registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
       addProfessionInfo OCTET STRING OPTIONAL
     }
상당히 복잡한 문서인증 구조를 현실화 한 것으로, 위의 ASN.1에서 구성된 내용을 Class화 하여 구성하였습니다. 구조가 복잡해 보이는데 실제로 복잡한 것이 맞습니다. (X.509에서 다루는 예외의 범위가 넓어서 클래스의 구성이 복잡해 집니다.)
각 명칭에 해당하는 Class들이 동일한 이름으로, 생성되어 있을 것을 볼 수 있습니다.


위의 테스트 코드에서 볼수 있 듯이, ASN.1 자체를 Spec에서 직접 처리하는 기능은 Bouncy Castle의 범위가 아닙니다.
정상적인 케이스를 테스트 하고, 의도한 비 정상적인 케이스를 테스트 합니다.


Asn1SequenceParserTest

단순 Asn1SquenceParser 테스트 항목입니다. 이래적으로 상속없이 분할 단위 테스트로 되어 있습니다. 이미 Spec을 통해 최종적으로 추측 가능한 byte 배열을 알고 있습니다. 이 배열값과, 생성한 class의 결과가 동일한지 여부를 확인하여 테스트 성공 실패 여부를 판단합니다.


* TestDerWriting
DER Sequence 데이터 쓰기의 결과를 확인합니다.
DerInteger
→ Der Encoding이 적용된 Integer입니다. 생성하기 위한 BigInteger는 별도로 다루겠습니다
DerObjectIdentifier
→ Object 식별자(OID)의 DER Encoding 적용 객체입니다.
DerSequenceGenerator
→ DER 형식으로 Sequence객체를 생성하도록 합니다.
*TestnestedDerWriting
중첩된 객체에 대한 쓰기 결과를 확인합니다. 사용된 객체는 동일하나 테스트 과정에서 중첩쓰기를 테스트 합니다. ( 해당 예제 코드를 살펴보면 이미 완성된 객체를 하위 요소로 갖는 객체의 쓰기를 중첩쓰기라고 합니다.)
* TestBerWriting
BER Sequence 객체의 쓰기를 테스트 합니다.
Element Type은 공통으로 사용 하기 때문에 동일한 객체를 재사용하며,
달라지는 부분은, BerSequenceGenerator를 사용한다는 점입니다.(ENCODING 형식만 변경)
* TestNestedBerWriting
BER Sequence의 중첩 쓰기를 테스트합니다. 테스트의 세부내용은 DER 버전과 동일합니다.
* TestDerReading
이전 테스트 데이터(seqData – byte array) 를 Asn1StreamParser로 읽어들인 후 처음 생성한 객체가 있는지 검사합니다.


Asn1StreamParser
→ 내부적으로 실제로 Tagging 정보를 확인하고 이를 통해서 BER, DER에 맞는 해당 Object를 읽어들일 있는 ReadObject() 항목을 구현합니다. Byte에서실제 객체로 변환하는 구조에 대한 항목은 StreamParser와 InputStream에 거의 구현되어 있다고 보셔도 무방합니다.


* TestNestedDerReading
이전의 Nested 데이터 검증용 데이터를 기반으로 중첩객체에 대한 데이터 읽기를 시도합니다.

BitStringTest



BitString은 ASN.1에서 각 비트에 특정한 별칭을 주는 형태로서, 일반적인 프로그래밍 언어에서 BitMask와 동일한 성격입니다.
실제 위의 코드는 상수값을 모르면 확인하기 어려운 부분들이 있습니다. 위에서는 X.509인증서 저장에서 사용되는 ASN.1의 별칭을 코드화 시킨것을 테스트 하는 코드를 담고 있습니다. 이런류의 소스 프로그램에서는 byte 단위의 실제 확인 과정이 매우 중요합니다. (우리 프로그램 끼리만 동작하는 – 정상적이지 않은 프로토콜, 스펙 구현을 상상해 보시면 잘 이해가 되실 것입니다.)


DerUtf8StringTest

DER로 Encoding된 UTF8String Class의 테스트입니다.
일반적인 문자열 Encoding 테스트와 유사한 방식을 사용합니다.



TimeTest

상대적으로 최근에 나온 ASN.1 Type인 Time에 대한 구현체를 테스트 하는 테스트 코드입니다.
실제적으로는 .Net의 UtcNow를 가지고 값을 비교하는 형태입니다.



위의 코드들이 주요 ElementClass에 대한 테스트 코드들이라고 생각하시면 됩니다. 나머지 ASN.1의 영역은 주로 Element Class에서 확장된 인증서나 추가 영역이라고 보시면되겠습니다. 테스트 코드들은 직접 소스를 살펴 보시기를 권장해 드립니다. 

2018년 12월 21일 금요일

BouncyCastle의 ASN.1 Abstract Classes

NameSpace

모든 필요한 부분들은 Org.BouncyCastle.Asn1 아래에 모여있습니다.


Spec에 없는 것들..

Spec 자체는 구현에 대해서 일일히 설명하지 않습니다. 대략적인 형태의 구성과 (ASN.1의 경우는 데이터를 저장하는 방법에 대한 추상 기술 형태이기 때문에 더더욱 그렇습니다.) 실제로 AsnNull 같은 형태는 Tag가 존재하고, 이를 표현할 Byte이외에는 실제소스에서 어떻게 하느냐는 자유롭습니다.


객체 살펴보기

앞 부분은 주로 추상 클래스에 대해서 언급 하고 있습니다. 실제 테스트 코드를 살펴 보기전에 추상클래스 부터 살펴보는 이유는 대부분의 기능이 추상클래스에서 시작하기 때문입니다.



Asn1OutputStream


FilterStream은 시스템의 일반 Stream을 프레임웍크에서 사용하기 좋도록 한번 더 감싼 Class이며, DerOutputStream은 TLV(Tag-Length-Value)를 실제로 구현한 부분입니다.
실제로 내부의 기본 Writing 동작은 DER Encoding을 기반으로 처리합니다.


Asn1Encodable



Asn1Object

이후에 기술할 모든 요소들의 근간이 되는 Class 입니다.
간단히 살펴보면, ByteArray 혹은 Stream에서 부터 생성이 가능합니다. 모든 요소들이 Byte로 부터 변경됨을 알 수있습니다. 이는 앞에서 살펴 본것과 같이, ASN.1 자체가 추상화된 데이터를 전송하기 위한 모델이기 때문입니다.

Asn1Null



ASN에서 NULL을 표현하기 위한 객체 입니다. 이후에 각 Encoding명칭 뒤에 Null이 있는 Class도 이 Class를 상속하여 만들어집니다. (Spec에서의 Tagging을 처리하기 위함입니다.)
내부 구현은 아무것도 없으며 오로지, ToString()이 Override 되어 있습니다.






Asn1OctetString



OctetSting에 대한 추상 Class입니다. 기본적인 비교연산자와, 객체 생성에 관련된 정적 class가 선언되어 있습니다. 실제 Encoding 객체에서는 다시 재활용됩니다.
Asn1OctecStringParser Interface
는 GetOctetStream()의 구현을 강제합니다.






Asn1Set

ASN1 Spec에서의 SET을 정의합니다.
전체 셋이 전송된 순서와 상관없이 같다면 같은 것으로 판단합니다. (내부적으로는 순서를 다시한번 정렬하여 확인합니다. - 정렬이라는 단어때문에 혼란할 수 있습니다. 실제로는 비교할때의 정렬을 의미합니다. - 문서상의 Spec에서 이야기하는 Sort는 전송의 원래 순서를 의미합니다. )

Asn1Sequence

ASN.1 SEQUENCE를 정의합니다. 전송한 순서가 유의미 하기때문에 같은 데이터를 구성요소를 가지는 배열이라 하더라도, 순서가 다르면 다른객체로 판단합니다. 속도상의 이유로 SET보다는 SEQUENCE를 활용하는 것이 일반적입니다. (Spec에서 제외된것은 아니며, 일반적으로 속도의 문제로 선택되는 것입니다.)


Asn1TaggedObject

ASN.1 표기법(Tag→Length→ Value)에 따르면 항상 시작은 Object의 종류를 지칭하는 TagNo로 시작됩니다. 이에 대한 정의는 별도로 Spec에 정의 되어 있으며 간략하게 정리하면 다음과 같습니다.
해당 부분은 Asn1Tags Class에 상수로 기술되어 있습니다.


    public class Asn1Tags
    {
        public const int Boolean = 0x01;
        public const int Integer = 0x02;
        public const int BitString = 0x03;
        public const int OctetString = 0x04;
        public const int Null = 0x05;
        public const int ObjectIdentifier = 0x06;
        public const int External = 0x08;
        public const int Enumerated = 0x0a;
        public const int Sequence = 0x10;
        public const int SequenceOf = 0x10; // for completeness
        public const int Set = 0x11;
        public const int SetOf = 0x11; // for completeness
        public const int NumericString = 0x12;
        public const int PrintableString = 0x13;
        public const int T61String = 0x14;
        public const int VideotexString = 0x15;
        public const int IA5String = 0x16;
        public const int UtcTime = 0x17;
        public const int GeneralizedTime = 0x18;
        public const int GraphicString = 0x19;
        public const int VisibleString = 0x1a;
        public const int GeneralString = 0x1b;
        public const int UniversalString = 0x1c;
        public const int BmpString = 0x1e;
        public const int Utf8String = 0x0c;
        public const int Constructed = 0x20;
        public const int Application = 0x40;
        public const int Tagged = 0x80;
    }


→ 실제로 이 정의들은 공식 Spec에 나와있는 것을 코드화 한 것 입니다.
Asn1TaggedObjectParser Interface의 구성은 다음과 같습니다.
     public interface Asn1TaggedObjectParser : IAsn1Convertible
     {
          int TagNo { get; }
          IAsn1Convertible GetObjectParser(int tag, bool isExplicit);
     }


이제까지의 객체 구현을 자세히 살펴보면 DER Encode이 왜 기준이 되는지 이해할 수 있을 것입니다.
이제 DER Encoding을 실로 구현한 객체들을 살펴 보도록 하겠습니다.
→ 여기 까지는 단위테스트가 실제로 이루어 질것이 별로 없습니다. 하위로 구성되어 있는 DER, BER 구현 단계가지 내려가야 실제단위테스트가 이루어 질 수 있습니다.

다음 글에서 뵙겠습니다.

BouncyCastle - ASN.1 살펴보기

 개요

BouncyCastle에서 전체 프로그램 구조를 살펴보다 보면, 가장 먼저 눈에 띄며 가장 전체적으로 참조가 많은 부분이 (소스코드 내부에서 ) ASN.1와 Crypto 라는 두개의 Namespace 입니다. 이 두 Namespace를 분석하기 전에 첫번째 항목인 ASN.1에 대해서 가볍게 살펴 보도록 하겠습니다.


ASN.1 이란?

Abstract Syntax Notation One의 줄임말로, 추상적 구문 구조를 기술하는 언어입니다.
좀 더 자세히 이야기 하면, 다양한 환경(하드웨어, OS, Platform)에 의존성이 없는 데이터 구성 / 정의에 대한 추상적 언어라는 의미입니다.


ASN.1의 특징



- 추상적인 기본 데이터 양식을 통해 다양한 데이터를 정의하는 것이 가능
- 비트 단위의 Encoding 방식에 대한 정의로 인해 개발자가 확장하기 용의하지 않음
- 추상적인 개념이기 때문에 실제 전송을 위해서는 별도의 실제 Encoding / Decoding 작업이 필요함.
관련 표준안 : ISO 8824 (ASN.1 문법 자체에 대한 내용)
ISO 8825 (추가 Encoding /Decoding)


참고 URL : https://www.itu.int/en/ITU-T/asn1/Pages/introduction.aspx


ASN.1 사용 예



* 공인인증서의 저장
* SNMP의 정보기술 및 Syntax 정의
* H.323의 인코딩 규칙 정의


ASN.1의 간략한 문법 소개

Module 선언 방식




모듈 명칭 {OBJECT IDENITIFIER} DEFINITIONS ::=
BEGIN
{
Type 선언
}
END

Type 선언 방식



Simple Type(ENUMERATED 제외) 일때,
변수명 ::= Type


구조 Type 일때(ENUMERATED 포함) 일때,
변수명 ::= Type {
Sub변수명1 SubType1,
…
}
공통 규칙은 한줄에 하나씩 선언한다는 것입니다.
값의 할당에 대한 예시는 각 Simple Type에서 설명하고 있습니다. 아래는 예는 모듈을 선언하고 그 안에 필요한 데이터 구조를 선언한 예시입니다.


모듈 선언 예시)
InventoryList {1 2 0 0 6 1} DEFINITIONS ::=
BEGIN
{
ItemId ::= SEQUENCE
{
partnumber IA5String,
quantity INTEGER,
wholesaleprice REAL,
saleprice REAL
}
StoreLocation ::= ENUMERATED
{
Baltimore (0),
Philadelphia (1),
Washington (2)
}
}
END



Simple Type

* BOOLEAN
→
일반적인 언어에서의 Boolean 값과 같습니다.
사용 예 ) isOpen BOOLEAN ::= TRUE
* INTEGER
→
일반적인 언어에서의 Integer와 같습니다.
사용 예 ) qty INTEGER (0..60) ::= 40
* BIT STRING
→ 일반적인 프로그램에서의 bitmask와 같습니다. 각 비트의 위치에 이름을 붙인다고 생각하시면 쉽습니다.
사용 예) Sensors ::= BIT STRING {
doorOpen(0),
windowOpen(1),
engineOn(2)
}
status Sensors ::= {windowOpen,engineOn}


* OCTET STRING
→ 8의 배수가 되는 bit수를 가진 binary 데이터를 표현하는 데이터입니다.
사용 예) MybinaryFile ::= OCTET STRING
* DATE
→
날짜에 대한 표현하는 형식으로 “YYYY-MM-DD” 양식으로 정의된 문자열 입니다.
사용 예) duDate DATE ::= “2018-11-11”
* TIME-OF-DAY
→ 시간을 표현하는 형식으로 “HH:MM:SS” 양식으로 정의된 문자열 입니다. 시간은 24시간 표시를 따릅니다.
사용 예) calledTime TIME-OF-DAY ::= “18:30:24”
* DATE-TIME
→
년월일시를 표현하는 형식이며, “YYYY-MM-DDTHH:MM:SS” 양식을 따릅니다.
사용 예) calledTime DATE-TIME ::= “2018-11-11T15:30:10”
* REAL
→ 10
진수 표시가 필요할 때 사용.
사용 예) Total ::= REAL
* ENUMERATED
→ 프로그램 언어에서의 Enum과 비슷한 개념이며, 반드시 시작 문자는 소문자여야 합니다.
사용 예) CarColors ::= ENUMERATED {black, red, white}
myCar CarColors ::= white
* OBJECT IDENTIFIER
→
세계적으로 고유한 식별자가 필요할 때 사용됩니다.( 미리 정의된 값들입니다. 대부분의 경우) 아래의 예는 미국의 최상위 인증기관을 의미합니다.
사용 예) {joint-iso-itu-t(2) country(16) us(840) organization(1)}
* IA5String
→ ASCII
와 제어문자가 포함된 문자열을 표현합니다.
* VisibleString
→ 제어문자를 제외한 ASCII 문자열을 표현합니다.
* NumericString
→
숫자와 Space만을 포함한 문자열을 표현합니다.
* UTF8String
→ UTF8Unicode 문자열을 표현합니다.
* NULL
→ 일반 언어에서의 NULL과 비슷한 개념입니다. 이후에 나오는 CHOICE에서 대체용으로 사용되거나, SEQUENCE 형식에서 선택적 컴포넌트를 지시합니다.


구조Type



* SEQUENCE
→ item
을 그룹으로 묶은 형태입니다. 보통의 다른 언어에서는 구조체와 같은 개념입니다. 내부적으로 Item들을 정렬합니다.(Spec 참고)
사용 예)
Contact ::= SEQUENCE {
name VisibleString,
phone NumericString
}
driver Contact ::= {name "J.Smith", phone "7325555555"}
* SEQUENCE OF
→ item이 반복되는 형식입니다. 프로그램 언어의 배열과 비슷한 개념입니다. 내부적으로 Item을 정렬합니다.
사용 예)
breakTimes SEQUENCE OF TIME-OF-DAY ::= {"10:00:00", "12:00:00", "14:45:00"}
* CHOICE
→ 기본적으로 다양한 아이템을 가지지만 한번에 하나의 아이템 만을 표현 할 수 있는 형식입니다.
사용 예)
Location ::= CHOICE {
streetAddress Address,
intersection Intersection,
landmark LandMarkName,
gpsCoordinates GpsInfo
}
meetAt Location ::= landmark: "Statue of Liberty"


사용이 중지된 타입



여러가지 이유로 아래의 타입들은 사용이 중지되었습니다.
* UTCTime
→ 2
자리 연도의 사용으로 세기의 구별이 모호해져 사용이 중지되었습니다.
* GeneralizedTime
→ TIME
형식의 등장으로 사용이 중단되었습니다.
* GraphicString, TeletexString
→
특정한 Charset을 지원하기 위한 Type이었으나, UTF8String이나 UniversalString과 같은 Type의 등장으로 사용 중지되었습니다.
* SET, SET OF
→ 객체가 발송될때의 순서가 그대로 유지되는 여부를 제외하고는 SEQUENCE,SEQUENCE OF와 동일하며, 순서가 보장되지 않기때문에 Encoding/Decoding에 드는 비용이 올라가고, 검증을 위해서 너무 복잡해지며, 일부 Encoding/Decoding에서는 반드시 순서를 다시 정리해야 하는 여러가지 이슈가 있어서 사용이 중지되었습니다.


ASN.1 Encoding 규칙 (Encoding Rules)

앞에서 소개한 바와 같이 ASN.1은 추상적인 데이터 정의언어이기 때문에, 물리적 전송계층에 그대로 반영할 수는 없습니다. 이렇게 정의된 언어를 물리적 데이터로 변환하는 방법이 Encoding 규칙 입니다. 다음과 같은 Encoding 규칙이 존재합니다. 개별적인 상세 내용들은 앞에 언급된 참조 문헌을 살펴보시기 바랍니다. 간단하게 특징을 정리하였습니다.


* BER(Basic Encoding Rules)
→
가장 오래된 구성 방식으로, Tag-Length-Value의 순으로 데이터를 Encoding 합니다.
이 전송방식은 기본적인 형태이며 실제로는 DER,CER로 구현됩니다.
* DER(Distinguished Encoding Rules)
→ BER
의 Subset입니다. 각 Element마다 TLV 형태의 값이 반복됩니다. DER은 X.509 인증서에 사용됩니다.
데이터가 많아지면 메타 데이터가 커집니다.
* CER(Canonical Encoding Rules)
→ BER
의 Subset 입니다. 길이를 알려주는 대신 데이터의 끝을 알려줍니다.
* OER(Octet Encoding Rules)
→ 가장 빠른 Encoding 규칙입니다. 8Bit 단위로 각 데이터의 엘리먼트를 처리하기 때문에 계산의 복잡도가 높지 않아 속도가 빠름니다.
* PER(Packed Encoding Rules)
→
가장 간단한 Encoding 규칙입니다. 고정된 값인 경우 TLV를 제거하여 전송량이 적습니다.
실제로 LTE등에 사용됩니다.
* XER(XML Encoding Rules), E-XER(Extended-XER)
→ XML
형식의 Encoding 규칙 입니다. E-XER는 XSD를 적용하기 쉽다는 차이점이 있습니다.
* JER(JSON Encoding Rules)
→ JSON 형식의 Encoding 방식입니다. XER이나 E-XER에 비해 더 사용하기 쉽습니다.
Debug
를 하거나 문제점을 파악하기에 용이합니다.


다음에는 개별 단위테스트를 통해 실제 소스를 살펴보도록 하겠습니다.



쿠버네티스 네트워크 정리

본 문서는 쿠버네티스의 공식문서( https://kubernetes.io/docs/concepts/cluster-administration/networking/ )의 일부를 번역하고 링크를 정리하여 붙이는 것에서 시작한 문서입니다. 일부 링크는 ...