| RFC 8949 | CBOR | 2020년 12월 |
| Bormann & Hoffman | 표준 트랙 | [페이지] |
간결한 이진 객체 표현(CBOR)은 설계 목표에 극히 작은 코드 크기, 비교적 작은 메시지 크기 및 버전 협상 없이도 확장할 수 있는 가능성이 포함되는 데이터 형식입니다. 이러한 설계 목표는 ASN.1 및 MessagePack과 같은 이전의 이진 직렬화와 구별되게 합니다.¶
이 문서는 RFC 7049를 폐기하며, RFC 7049의 교환 형식과 완전한 호환성을 유지하면서 편집상 개선, 새로운 세부 사항 및 정오표 수정을 제공합니다. 이는 형식의 새 버전을 만들지 않습니다.¶
이것은 인터넷 표준 트랙 문서입니다.¶
이 문서는 인터넷 엔지니어링 태스크 포스 (IETF)의 산출물입니다. 이는 IETF 커뮤니티의 합의를 나타냅니다. 공개 검토를 받았으며 인터넷 엔지니어링 운영 그룹(IESG)에 의해 출판이 승인되었습니다. 인터넷 표준에 관한 자세한 정보는 RFC 7841의 섹션 2에서 확인할 수 있습니다.¶
이 문서의 현재 상태, 모든 정오표 및 이에 대한 피드백 제공 방법에 관한 정보는 https://www.rfc-editor.org/info/rfc8949에서 확인할 수 있습니다.¶
Copyright (c) 2020 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.¶
구조화된 데이터의 이진 표현 (이진 직렬화 형식이라고도 함)을 위한 표준화된 형식은 수백 가지가 있다. 그중 일부는 특정 정보 영역을 위한 것이며, 다른 일부는 임의의 데이터를 위해 일반화되어 있다. IETF에서 후자의 범주에서 가장 잘 알려진 형식은 아마도 ASN.1의 BER 및 DER [ASN.1]일 것이다.¶
여기에서 정의하는 형식은 현재 형식들이 잘 충족하지 못하는 몇 가지 특정 설계 목표를 따른다. 기본 데이터 모델은 JSON 데이터 모델 [RFC8259]의 확장된 버전이다. 이는 RFC 8259의 문법을 일반적으로 확장하자는 제안이 아니라는 점에 유의하는 것이 중요하다. 그렇게 하면 이미 배포된 JSON 문서와 상당한 하위 호환성 문제가 발생하기 때문이다. 대신, 이 문서는 단순히 JSON에서 출발하는 자체 데이터 모델을 정의한다.¶
부록 E는 일부 기존 이진 형식을 나열하고 이들이 간결한 이진 객체 표현(CBOR)의 설계 목표에 얼마나 잘 부합하거나 부합하지 않는지 논의한다.¶
이 문서는 [RFC7049]를 폐기하며, RFC 7049의 교환 형식과 완전한 호환성을 유지하면서 편집상 개선, 새로운 세부 사항 및 정오표 수정을 제공한다. 이는 형식의 새 버전을 만들지 않는다.¶
CBOR의 목표는 중요도가 대체로 높은 것부터 낮은 것까지 다음과 같다.¶
표현은 인터넷 표준에서 사용되는 대부분의 일반적인 데이터 형식을 모호하지 않게 인코딩할 수 있어야 한다.¶
인코더 또는 디코더의 코드는 매우 제한적인 메모리, 프로세서 성능, 명령어 집합을 가진 시스템을 지원하기 위해 간결할 수 있어야 한다.¶
데이터는 스키마 설명 없이 디코딩될 수 있어야 한다.¶
직렬화는 합리적으로 간결해야 하지만, 데이터 간결성은 인코더와 디코더의 코드 간결성에 비해 부차적이다.¶
이 형식은 제약 노드와 대용량 애플리케이션 모두에 적용 가능해야 한다.¶
이 형식은 JSON과의 상호 변환을 위해 모든 JSON 데이터 타입을 지원해야 한다.¶
이 형식은 확장 가능해야 하며, 확장된 데이터는 이전 디코더가 디코딩할 수 있어야 한다.¶
이 문서에서 사용되는 핵심 단어 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", 및 "OPTIONAL"은 여기에 표시된 것처럼 모두 대문자로 나타날 때에만 BCP 14 [RFC2119] [RFC8174]에 설명된 대로 해석되어야 한다.¶
"byte"라는 용어는 이제 관례적인 의미로 "octet"의 동의어로 사용된다. 모든 다중 바이트 값은 네트워크 바이트 순서 (즉, 최상위 바이트가 먼저 오는 방식, "빅 엔디언"이라고도 함)로 인코딩된다.¶
이 명세는 다음 용어를 사용한다.¶
Infinity, NaN (숫자가 아님), 음의 0, 비정규수와 같은 부동소수점 값에 대한 용어와 개념은 [IEEE754]에 정의되어 있다.¶
비트 산술이나 데이터 타입이 설명되는 곳에서, 이 문서는 프로그래밍 언어 C [C]에서 익숙한 표기법을 사용한다. 다만 ".."는 주어진 양 끝을 모두 포함하는 범위를 나타내며, 위첨자 표기법은 거듭제곱을 나타낸다. 예를 들어, 2의 64제곱은 다음과 같이 표기한다: 264. 이 명세의 일반 텍스트 버전에서는 위첨자 표기법을 사용할 수 없으므로 대체 표기법으로 렌더링된다. 그 표기법은 이 RFC에 최적화되어 있지 않으며, 불행히도 C의 배타적 OR(부록에서만 사용되고, 부록은 거듭제곱을 사용하지 않음)와 모호하고 일반 텍스트 버전의 독자에게 주의를 요구한다.¶
예제와 의사 코드는 부호 있는 정수가 2의 보수 표현을 사용하고 부호 있는 정수의 오른쪽 시프트가 부호 확장을 수행한다고 가정한다. 이러한 가정은 현재 최종 초안으로 제공되는 2020년 버전 C++의 섹션 6.8.1 (basic.fundamental) 및 7.6.7 (expr.shift)에도 명시되어 있다 [Cplusplus20].¶
16진수에 대한 "0x" 표기와 유사하게, 이진 표기의 숫자는 "0b"가 앞에 붙는다. 밑줄은 오직 가독성을 위해 숫자에 추가될 수 있으므로, 0b00100001 (0x21)은 바이트의 비트에 대한 원하는 해석을 강조하기 위해 0b001_00001로 쓸 수 있다. 이 경우 세 비트와 다섯 비트로 나뉜다. 인코딩된 CBOR 데이터 항목은 때때로 "0x" 또는 "0b" 표기로 주어진다. 이 값들은 먼저 C에서와 같이 숫자로 해석된 다음, 표기에 표현된 모든 선행 0 바이트를 포함하여 네트워크 바이트 순서의 바이트 문자열로 해석된다.¶
단어는 강조를 위해 기울임꼴로 표시될 수 있다. 이 명세의 일반 텍스트
형식에서는 단어를 밑줄 문자로 둘러싸는 방식으로 이를 표시한다.
축어 텍스트(예: 프로그래밍 언어의 이름)는
monospace 글꼴로 표시될 수 있다. 일반 텍스트에서는
텍스트를 큰따옴표로 둘러싸는 방식으로 다소 모호하게 근사한다
(큰따옴표는 또한 일반적인 의미도 유지한다).¶
CBOR는 일반 데이터 모델에 대해 명시적이다. 이 모델은 CBOR에서 표현할 수 있는 모든 데이터 항목의 집합을 정의한다. 기본 일반 데이터 모델은 "단순 값" 및 태그의 등록을 통해 확장 가능하다. 그러면 애플리케이션은 결과적으로 확장된 일반 데이터 모델의 하위 집합을 만들어 자체 특정 데이터 모델을 구축할 수 있다.¶
일반 데이터 모델의 데이터 항목을 표현할 수 있는 환경 내에서는 일반 CBOR 인코더와 디코더를 구현할 수 있다 (일반적으로는 환경에 자연스러운 표현이 아직 없는 데이터 항목에 대해 추가 구현 데이터 타입을 정의하는 것을 포함한다). 일반 인코더와 디코더를 제공할 수 있는 능력은 CBOR의 명시적인 설계 목표이다. 그러나 많은 애플리케이션은 자체 애플리케이션별 인코더 및/또는 디코더를 제공할 것이다.¶
섹션 3에 정의된 기본(확장되지 않은) 일반 데이터 모델에서, 데이터 항목은 다음 중 하나이다.¶
이 모델에서 정수와 부동소수점 값은 같은 수치 값을 갖더라도 서로 구별된다는 점에 유의한다.¶
또한 직렬화 변형은 일반 데이터 모델 수준에서 보이지 않는다는 점에 유의한다. 이러한 의도적인 비가시성에는 인코딩된 부동소수점 값의 바이트 수가 포함된다. 또한 정수의 인코딩, 텍스트 또는 바이트 문자열 길이의 인코딩, 배열의 요소 수 또는 맵의 쌍 수에 대한 인코딩, 또는 태그 번호의 인코딩과 같은 "인수"(섹션 3 참조)의 인코딩 선택도 포함된다.¶
이 기본 일반 데이터 모델은 이 문서에서 다음과 같은 여러 단순 값과 태그 번호의 등록을 통해 확장되었다.¶
false, true, null, 및 undefined
(20..23으로 식별되는 단순 값, 섹션 3.3)¶
확장된 일반 데이터 모델의 추가 요소는 CBOR를 위해 생성된 IANA 레지스트리를 통해 정의될 수 있다(그리고 이미 정의되어 왔다). 그러한 확장을 일반 인코더나 디코더가 알지 못하더라도, 그 확장을 사용하는 데이터 항목은 기본 일반 데이터 모델 내에서, 즉 일반 단순 값 또는 일반 태그로 표현하여 애플리케이션으로 또는 애플리케이션에서 전달될 수 있다.¶
다시 말해, 기본 일반 데이터 모델은 이 문서에 정의된 대로 안정적이며, 확장된 일반 데이터 모델은 새 단순 값 또는 태그 번호의 등록을 통해 확장되지만 결코 축소되지 않는다.¶
일반 인코더와 디코더가
false, true, 및 null
(undefined는 의도적으로
제외됨)을 해당 프로그래밍 환경에 적합한 형태로
표현할 수 있으리라는 강한 기대가 있지만,
태그로 생성된 데이터 모델 확장의 구현은 실제로
선택 사항이며 구현 품질의 문제이다.¶
CBOR 기반 프로토콜의 특정 데이터 모델은 일반적으로 확장된 일반 데이터 모델의 하위 집합을 취하고, 이 하위 집합 및 그 구성 요소 내의 데이터 항목에 애플리케이션 의미를 부여한다. 그러한 특정 데이터 모델을 문서화하고 데이터 항목의 타입을 명시할 때는, CBOR 표현의 측면("주요 타입 1", "주요 타입 4")을 참조하기보다는 일반 데이터 모델 이름("음의 정수", "배열")으로 타입을 식별하는 것이 바람직하다.¶
특정 데이터 모델은 또한
맵 키 및 인코더 자유도를 위해 (서로 다른 타입의 값을 포함하여)
값의 동등성을 지정할 수 있다. 예를 들어, 일반 데이터 모델에서는 유효한 맵이
0과
0.0을 모두 키로 가질 수 있으며, 인코더는 MUST NOT
0.0을 정수
(주요 타입 0, 섹션 3.1)로 인코딩해서는 안 된다. 그러나 특정 데이터
모델이 정수 값을 갖는 부동소수점 표현과 정수 표현이
동등하다고 선언한다면, 단일 맵에서 0과 0.0을 모두 맵 키로 사용하는 것은
서로 다른 주요 타입으로 인코딩되었더라도
중복으로 간주되어 유효하지 않게 된다. 또한 인코더는 인코딩 바이트를 절약하기 위해
정수 값을 갖는
부동소수점을 정수로, 또는 그 반대로 인코딩할 수 있다.¶
CBOR 데이터 항목(섹션 2)은 이 섹션에 설명된 대로 올바른 형식의 인코딩된 데이터 항목을 담는 바이트 문자열로 인코딩되거나 그로부터 디코딩된다. 인코딩은 부록 B의 표 7에 초기 바이트를 기준으로 요약되어 있다. 인코더는 MUST 올바른 형식의 인코딩된 데이터 항목만 생성해야 한다. 디코더는 올바른 형식의 인코딩된 CBOR 데이터 항목이 아닌 입력을 만났을 때 디코딩된 데이터 항목을 반환해서는 MUST NOT 안 된다 (이는 손상된 인코딩된 CBOR 데이터 항목에서 일부 정보를 사용할 수 있게 하는 진단 및 복구 도구의 유용성을 떨어뜨리지 않는다).¶
각 인코딩된 데이터 항목의 초기 바이트는 주요 타입(상위 3비트, 섹션 3.1에서 설명됨)에 대한 정보와 추가 정보(하위 5비트)를 모두 포함한다. 몇 가지 예외를 제외하고, 추가 정보의 값은 부호 없는 정수 "인수"를 로드하는 방법을 설명한다.¶
초기 바이트와 인수를 구성하기 위해 소비되는 모든 추가 바이트를 통틀어 데이터 항목의 헤드라고 한다.¶
이 인수의 의미는 주요 타입에 따라 달라진다. 예를 들어, 주요 타입 0에서 인수는 데이터 항목 자체의 값이며(주요 타입 1에서는 데이터 항목의 값이 인수로부터 계산된다), 주요 타입 2와 3에서는 이어지는 바이트의 문자열 데이터 길이를 제공하고, 주요 타입 4와 5에서는 포함된 데이터 항목 수를 결정하는 데 사용된다.¶
인코딩된 바이트 시퀀스가 데이터 항목의 끝에 도달하기 전에 끝나면, 그 항목은 올바른 형식이 아니다. 최외곽 인코딩된 항목이 디코딩된 후에도 인코딩된 바이트 시퀀스에 바이트가 남아 있으면, 그 인코딩은 단일 올바른 형식의 CBOR 항목이 아니다. 애플리케이션에 따라 디코더는 이 인코딩을 올바른 형식이 아닌 것으로 처리하거나 남은 바이트의 시작 위치를 애플리케이션에 알려줄 수 있다.¶
CBOR 디코더 구현은 초기 바이트의 256개 정의된 값 전체에 대한 점프 테이블(표 7)을 기반으로 할 수 있다. 제약 구현의 디코더는 보다 간결한 코드를 위해 초기 바이트와 이어지는 바이트의 구조를 대신 사용할 수 있다 (이것이 어떻게 보일 수 있는지에 대한 대략적인 인상은 부록 C 참조).¶
다음은 주요 타입과 그 타입에 관련된 추가 정보 및 기타 바이트를 나열한다.¶
이 여덟 가지 주요 타입은 데이터 항목의 초기 바이트에 대해 가능한 256개 값 중 어떤 값이 사용되는지를 보여 주는 간단한 표(표 7)로 이어진다.¶
주요 타입 6과 7에서는 가능한 값 중 다수가 향후 명세를 위해 예약되어 있다. 이 값들에 대한 자세한 정보는 섹션 9를 참조한다.¶
표 1은 당분간 섹션 3.2를 무시하고 CBOR가 정의한 주요 타입을 요약한다. 이 표의 숫자 N은 인수를 나타낸다.¶
| 주요 타입 | 의미 | 내용 |
|---|---|---|
| 0 | 부호 없는 정수 N | - |
| 1 | 음의 정수 -1-N | - |
| 2 | 바이트 문자열 | N바이트 |
| 3 | 텍스트 문자열 | N바이트(UTF-8 텍스트) |
| 4 | 배열 | N개의 데이터 항목(요소) |
| 5 | 맵 | 2N개의 데이터 항목(키/값 쌍) |
| 6 | 번호 N의 태그 | 1개의 데이터 항목 |
| 7 | 단순/부동소수점 | - |
네 가지 CBOR 항목(배열, 맵, 바이트 문자열 및 텍스트 문자열)은 추가 정보 값 31을 사용하여 부정 길이로 인코딩될 수 있다. 이는 배열이나 맵 내부의 항목 수 또는 문자열의 총 길이를 알기 전에 항목의 인코딩을 시작해야 할 때 유용하다. (데이터 항목이 모두 알려지기 전에 전송을 시작할 수 있는 능력은 종종 그 데이터 항목 내의 "스트리밍"이라고 한다.)¶
부정 길이 배열과 맵은 부정 길이 문자열(바이트 문자열과 텍스트 문자열)과는 다르게 처리된다.¶
"break" 정지 코드는 주요 타입 7과 추가 정보 값 31(0b111_11111)로 인코딩된다. 이는 그 자체가 데이터 항목이 아니다. 단지 부정 길이 항목을 닫기 위한 구문적 기능이다.¶
"break" 정지 코드가 부정 길이 문자열, 배열 또는 맵의 바로 내부가 아닌, 데이터 항목이 예상되는 곳에 나타나면 -- 예를 들어 정길이 배열이나 맵 바로 내부 -- 포함하는 항목은 올바른 형식이 아니다.¶
부정 길이 배열과 맵은 추가 정보 값 31을 가진 해당 주요 타입을 사용하고, 그 뒤에 배열의 경우 0개 이상의 항목, 맵의 경우 키/값 쌍의 임의 길이 시퀀스가 이어지며, "break" 정지 코드(섹션 3.2.1)로 끝나는 방식으로 표현된다. 다시 말해, 부정 길이 배열과 맵은 추가 정보 값 31로 시작하고 "break" 정지 코드로 끝난다는 점을 제외하면 다른 배열 및 맵과 동일하게 보인다.¶
"break" 정지 코드가 맵에서 키 뒤에 나타나, 그 키의 값 대신 위치하면, 맵은 올바른 형식이 아니다.¶
부정 길이 배열 또는 맵 항목을 중첩하는 것에 대한 제한은 없다. "break"는 단일 항목만 종료하므로, 중첩된 부정 길이 항목은 부정 길이 항목을 시작하는 타입 바이트 수만큼 정확히 많은 "break" 정지 코드를 필요로 한다.¶
예를 들어, 인코더가 추상 배열 [1, [2, 3], [4, 5]]를 표현하려고 한다고 가정한다. 정길이 인코딩은 0x8301820203820405가 된다.¶
83 -- Array of length 3
01 -- 1
82 -- Array of length 2
02 -- 2
03 -- 3
82 -- Array of length 2
04 -- 4
05 -- 5
¶
부정 길이 인코딩은 필요에 따라 이 데이터 항목에서 인코딩된 세 배열 각각에 독립적으로 적용될 수 있으며, 다음과 같은 표현으로 이어진다.¶
0x9f018202039f0405ffff
9F -- Start indefinite-length array
01 -- 1
82 -- Array of length 2
02 -- 2
03 -- 3
9F -- Start indefinite-length array
04 -- 4
05 -- 5
FF -- "break" (inner array)
FF -- "break" (outer array)
¶
0x9f01820203820405ff
9F -- Start indefinite-length array
01 -- 1
82 -- Array of length 2
02 -- 2
03 -- 3
82 -- Array of length 2
04 -- 4
05 -- 5
FF -- "break"
¶
0x83018202039f0405ff
83 -- Array of length 3
01 -- 1
82 -- Array of length 2
02 -- 2
03 -- 3
9F -- Start indefinite-length array
04 -- 4
05 -- 5
FF -- "break"
¶
0x83019f0203ff820405
83 -- Array of length 3
01 -- 1
9F -- Start indefinite-length array
02 -- 2
03 -- 3
FF -- "break"
82 -- Array of length 2
04 -- 4
05 -- 5
¶
부정 길이 맵(우연히 두 개의 키/값 쌍을 가짐)의 예는 다음과 같을 수 있다.¶
0xbf6346756ef563416d7421ff
BF -- Start indefinite-length map
63 -- First key, UTF-8 string length 3
46756e -- "Fun"
F5 -- First value, true
63 -- Second key, UTF-8 string length 3
416d74 -- "Amt"
21 -- Second value, -2
FF -- "break"
¶
부정 길이 문자열은 바이트 문자열 또는 텍스트 문자열에 대한 주요 타입과 추가 정보 값 31을 포함하는 바이트로 표현되며, 그 뒤에 지정된 타입의 정길이 문자열("청크")이 0개 이상 이어지고, "break" 정지 코드(섹션 3.2.1)로 끝난다. 부정 길이 문자열이 나타내는 데이터 항목은 청크들의 연결이다. 청크가 없으면 데이터 항목은 지정된 타입의 빈 문자열이다. 길이가 0인 청크는 특별히 유용하지는 않지만 허용된다.¶
부정 길이 문자열 표시자 (0b010_11111 또는 0b011_11111)와 "break" 정지 코드 사이의 항목 중 같은 주요 타입의 정길이 문자열 항목이 아닌 것이 있다면, 그 문자열은 올바른 형식이 아니다.¶
이 설계는 부정 길이 문자열을 부정 길이 문자열의 청크로 중첩하는 것을 허용하지 않는다. 허용한다면 디코더 구현이 중첩 수준의 스택이나 최소한 카운트를 유지해야 한다. 인코더 쪽에서는 내부 부정 길이 문자열이 청크로 구성될 것이며, 이러한 청크를 대신 외부 부정 길이 문자열에 직접 넣을 수 있기 때문에 불필요하다.¶
부정 길이 텍스트 문자열 내부의 정길이 텍스트 문자열 중 유효하지 않은 것이 있다면, 부정 길이 텍스트 문자열은 유효하지 않다. 이는 단일 Unicode 코드 포인트(스칼라 값)의 UTF-8 바이트가 청크 사이에 나뉘어질 수 없음을 의미한다는 점에 유의한다. 텍스트 문자열의 새 청크는 코드 포인트 경계에서만 시작될 수 있다.¶
예를 들어, 다음 바이트들로 구성된 인코딩된 데이터 항목을 가정한다.¶
0b010_11111 0b010_00100 0xaabbccdd 0b010_00011 0xeeff99 0b111_11111
5F -- Start indefinite-length byte string
44 -- Byte string of length 4
aabbccdd -- Bytes content
43 -- Byte string of length 3
eeff99 -- Bytes content
FF -- "break"
¶
디코딩 후, 이는 7바이트를 가진 하나의 바이트 문자열 0xaabbccddeeff99가 된다.¶
표 2는 CBOR가 정의한 주요 타입이 부정 길이 인코딩(추가 정보가 31로 설정됨)에 사용되는 방식을 요약한다.¶
| 주요 타입 | 의미 | "break" 정지 코드까지 포함되는 것 |
|---|---|---|
| 0 | (올바른 형식이 아님) | - |
| 1 | (올바른 형식이 아님) | - |
| 2 | 바이트 문자열 | 정길이 바이트 문자열 |
| 3 | 텍스트 문자열 | 정길이 텍스트 문자열 |
| 4 | 배열 | 데이터 항목(요소) |
| 5 | 맵 | 데이터 항목(키/값 쌍) |
| 6 | (올바른 형식이 아님) | - |
| 7 | "break" 정지 코드 | - |
주요 타입 7은 두 종류의 데이터, 즉 부동소수점 수와 내용을 필요로 하지 않는 "단순 값"을 위한 것이다. 초기 바이트의 5비트 추가 정보 값 각각은 표 3에 정의된 대로 별도의 의미를 가진다. 정수에 대한 주요 타입과 마찬가지로, 이 주요 타입의 항목은 내용 데이터를 담지 않는다. 모든 정보는 초기 바이트(헤드)에 있다.¶
| 5비트 값 | 의미 |
|---|---|
| 0..23 | 단순 값(값 0..23) |
| 24 | 단순 값(이어지는 바이트의 값 32..255) |
| 25 | IEEE 754 반정밀도 부동소수점(16비트가 뒤따름) |
| 26 | IEEE 754 단정밀도 부동소수점(32비트가 뒤따름) |
| 27 | IEEE 754 배정밀도 부동소수점(64비트가 뒤따름) |
| 28-30 | 예약됨, 현재 문서에서는 올바른 형식이 아님 |
| 31 | 부정 길이 항목에 대한 "break" 정지 코드 (섹션 3.2.1) |
다른 모든 주요 타입과 마찬가지로, 5비트 값 24는 단일 바이트 확장을 의미한다. 즉, 단순 값을 표현하기 위해 추가 바이트가 뒤따른다. (혼동을 최소화하기 위해 32에서 255까지의 값만 사용된다.) 이는 초기 바이트의 구조를 유지한다. 다른 주요 타입과 마찬가지로, 그 길이는 항상 첫 번째 바이트의 추가 정보에 의존한다. 표 4는 단순 값에 할당되고 사용할 수 있는 숫자 값을 나열한다.¶
인코더는 0xf8(주요 타입 7, 추가 정보 24)로
시작하고 0x20(십진수 32)보다 작은 바이트가 이어지는 2바이트 시퀀스를
내보내서는 MUST NOT 안 된다. 그러한 시퀀스는
올바른 형식이 아니다. (이는 인코더가 false, true,
null, 또는 undefined를 2바이트 시퀀스로 인코딩할 수 없으며
이들의 1바이트 변형만 올바른 형식임을 의미한다. 더 일반적으로 말하면,
각 단순 값은 단 하나의 표현 변형만 가진다.)¶
5비트 값 25, 26, 27은 16비트, 32비트, 64비트 IEEE 754 이진 부동소수점 값 [IEEE754]을 위한 것이다. 이러한 부동소수점 값은 적절한 크기의 추가 바이트에 인코딩된다. (16비트 부동소수점 수에 대한 일부 정보는 부록 D를 참조한다.)¶
데이터 모델 수준의 일부 값에 대해 CBOR는 여러 직렬화를 제공한다. 많은 애플리케이션에서는 인코더가 항상 선호 직렬화(선호 인코딩)를 선택하는 것이 바람직하다. 그러나 현재 명세는 이 선호를 강제하는 부담을 인코더나 디코더 어느 쪽에도 지우지 않는다.¶
일부 제약 디코더는 비선호 직렬화를 디코딩하는 능력이 제한될 수 있다. 예를 들어, 어떤 애플리케이션에서 1_000_000_000(십억) 미만의 정수만 예상된다면, 디코더는 정수의 64비트 인수를 디코딩하는 데 필요한 코드를 생략할 수 있다. 항상 선호 직렬화("선호 인코더")를 사용하는 인코더는 이 애플리케이션에서 발생할 수 있는 숫자에 대해 이 디코더와 상호 운용된다. 일반적으로 말해, 선호 인코더는 예컨대 항상 64비트 정수를 사용하는 인코더보다 더 보편적으로 상호 운용 가능하며 또한 낭비도 적다.¶
마찬가지로, 제약 인코더는 지원하는 표현 변형의 다양성이 제한되어 선호 직렬화를 내보내지 않을 수 있다("변형 인코더"). 예를 들어, 제약 인코더는 더 짧은 표현을 사용할 수 있더라도 자신이 인코딩하는 정수에 대해 항상 32비트 변형을 사용하도록 설계될 수 있다(64비트 변형으로만 표현할 수 있는 정수가 애플리케이션에 필요하지 않다고 가정). 선호 직렬화만 수신한다고 가정하지 않는 디코더 ("변형 허용 디코더")는 따라서 더 보편적으로 상호 운용 가능하다고 할 수 있다(다만 선호 직렬화를 수신하는 경우에 최적화할 수도 있다). CBOR 디코더의 완전한 구현은 정의상 변형 허용적이다. 이 구분은 CBOR 디코더의 제약 구현이 변형 인코더를 만나는 경우에만 관련된다.¶
선호 직렬화는 항상 인수(섹션 3)를 표현하는 가장 짧은 형식을 사용한다. 또한 인코딩되는 값을 보존하는 가장 짧은 부동소수점 인코딩을 사용한다.¶
부동소수점 값에 대한 선호 직렬화는 그 값을 보존하는 가장 짧은 부동소수점 인코딩이다. 예를 들어 숫자 5.5는 0xf94580, 숫자 5555.5는 0xfa45ad9c00이다. NaN 값의 경우, 더 짧은 가수를 오른쪽으로 0으로 채웠을 때 원래 NaN 값이 재구성된다면 더 짧은 인코딩이 선호된다 (많은 애플리케이션에서는 단일 NaN 인코딩 0xf97e00이면 충분하다).¶
항목의 직렬화가 시작되는 시점에 길이를 알고 있다면 항상 정길이 인코딩이 선호된다.¶
일부 프로토콜은 인코더가 특정한 결정적 형식의 CBOR만 내보내기를 원할 수 있다. 그러한 프로토콜은 또한 디코더가 입력이 그 결정적 형식인지 확인하게 할 수도 있다. 그러한 프로토콜은 "결정적 형식"이 무엇을 의미하는지, 그리고 인코더와 디코더가 무엇을 해야 하는지를 자유롭게 정의할 수 있다. 이 섹션은 그러한 결정적 형식의 기반이 될 수 있는 제한 집합을 정의한다.¶
CBOR 인코딩은 다음 제한을 만족하면 "핵심 결정적 인코딩 요구 사항"을 만족한다.¶
선호 직렬화를 사용해야 MUST 한다. 특히 이는 정수, 주요 타입 2부터 5까지의 길이, 그리고 태그에 대한 인수(섹션 3 참조)가 가능한 한 짧아야 MUST 함을 의미한다. 예를 들면 다음과 같다.¶
부동소수점 값도 그 값을 보존하는 가장 짧은 형식을 사용해야 MUST 한다. 예를 들어 1.5는 0xf93e00(binary16)으로, 1000000.5는 0xfa49742408(binary32)로 인코딩된다. (이를 구현하는 한 방법은 모든 부동소수점을 64비트 부동소수점으로 시작하게 한 다음, 32비트 부동소수점으로 시험 변환을 수행하는 것이다. 결과가 같은 수치 값이면 더 짧은 형식을 사용하고, 16비트 부동소수점으로의 시험 변환으로 이 과정을 반복한다. 이는 양의 Infinity 및 음의 Infinity에 대해 16비트 부동소수점을 선택하는 데도 동작한다.)¶
모든 맵의 키는 그 결정적 인코딩의 바이트 단위 사전식 순서로 정렬되어야 MUST 한다. 예를 들어, 다음 키들은 올바르게 정렬되어 있다.¶
CBOR 태그는 결정적 인코딩에 대해 추가 고려 사항을 제시한다. CBOR 기반 프로토콜이 특정 태그의 존재와 부재에 대해 동일한 의미를 제공한다면(예: 날짜/시간 위치에서 태그 1 데이터 항목과 원시 숫자를 모두 허용하고 후자를 태그가 붙은 것처럼 처리), 결정적 형식은 "가장 짧은 형식" 원칙에 따라 태그의 존재를 허용하지 않을 것이다. 예를 들어, 어떤 프로토콜은 인코더에게 URL을 텍스트 문자열로 표현하거나, 섹션 3.4.5.3을 사용하여 텍스트 문자열을 포함하는 태그 번호 32로 표현하는 선택권을 줄 수 있다. 이 프로토콜의 결정적 인코딩은 태그가 존재해야 한다고 요구하거나 태그가 없어야 한다고 요구해야 하며, 둘 중 아무 것이나 허용해서는 안 된다.¶
특정 위치에서 특정 의미를 얻기 위해 태그를 요구하는 프로토콜에서는, 그 태그도 결정적 형식에 나타나야 한다. 결정적 인코딩 고려 사항은 태그의 내용에도 적용된다.¶
프로토콜에 태그 번호 2 또는 3 (섹션 3.4.3)을 사용하여 절댓값이 264 이상인 정수를 표현할 수 있는 필드가 포함되어 있다면, 그 프로토콜의 결정적 인코딩은 더 작은 정수도 이러한 태그를 사용하여 표현할지, 또는 주요 타입 0과 1을 사용하여 표현할지를 지정해야 한다. 선호 직렬화는 후자의 선택을 사용하므로, 이것이 권장된다.¶
기본 부동소수점 값(섹션 3.3)이나 태그(또는 둘 모두)를 사용하여 표현되는 부동소수점 값을 포함하는 프로토콜은, 다음과 같은 결정적 인코딩에 대한 추가 요구 사항을 정의해야 할 수 있다.¶
프로토콜에 부동소수점 값을 표현할 수 있는 필드가 포함되어 있고, 정수와 부동소수점 값을 서로 바꿔 쓸 수 있다고 선언하는 특정 데이터 모델이 있다면, 그 프로토콜의 결정적 인코딩은 예를 들어 정수 1.0이 0x01(부호 없는 정수), 0xf93c00(binary16), 0xfa3f800000(binary32), 또는 0xfb3ff0000000000000(binary64) 중 무엇으로 인코딩되는지를 지정해야 한다. 이에 대한 예시 규칙은 다음과 같다.¶
규칙 1은 정수와 부동소수점 값 사이의 경계를 걸치고, 규칙 3은 선호 직렬화를 사용하지 않으므로, 많은 경우 규칙 2가 좋은 선택일 수 있다.¶
핵심 결정적 인코딩 요구 사항(섹션 4.2.1)은 섹션 3.9 of [RFC7049]에서 제안된 순서 (그곳에서는 "Canonical CBOR"라고 불림)와 다른 순서로 맵 키를 정렬한다. [RFC7049]에 지정된 순서와 호환되어야 하는 프로토콜은 대신 이 명세의 "길이 우선 핵심 결정적 인코딩 요구 사항"의 관점에서 지정될 수 있다.¶
CBOR 인코딩은 핵심 결정적 인코딩 요구 사항을 만족하되, 모든 맵의 키가 다음과 같이 정렬되어야 MUST 한다는 점만 다르면 "길이 우선 핵심 결정적 인코딩 요구 사항"을 만족한다.¶
예를 들어, 길이 우선 핵심 결정적 인코딩 요구 사항에 따르면 다음 키들은 올바르게 정렬되어 있다.¶
CBOR와 같은 데이터 형식은 형식 협상이 없는 환경에서 자주 사용된다. CBOR의 특정 설계 목표는 포함되거나 가정된 스키마를 전혀 필요로 하지 않는 것이다. 디코더는 CBOR 항목을 가져와 다른 지식 없이 디코딩할 수 있다.¶
물론 실제 구현에서는 인코더와 디코더가 CBOR 데이터 항목에 무엇이 있어야 하는지에 대해 공유된 관점을 갖게 된다. 예를 들어, 합의된 형식은 "항목은 첫 번째 값이 UTF-8 문자열이고, 두 번째 값이 정수이며, 이후 값은 0개 이상의 부동소수점 수인 배열이다" 또는 "항목은 키로 바이트 문자열을 가지고, 키가 0xab01인 쌍을 포함하는 맵이다"일 수 있다.¶
CBOR 기반 프로토콜은 디코더가 유효하지 않거나 기타 예상치 못한 데이터를 어떻게 처리하는지 지정해야 MUST 한다. CBOR 기반 프로토콜은 임의의 유효한 데이터를 예상치 못한 것으로 취급한다고 지정할 MAY 수 있다. CBOR 기반 프로토콜의 인코더는 유효한 항목만 생성해야 MUST 한다. 즉, 프로토콜은 유효하지 않은 항목을 사용하도록 설계될 수 없다. 인코더는 자신이 사용되는 프로토콜에 필요한 만큼 많거나 적은 타입의 값을 인코딩할 수 있으며, 디코더는 자신이 사용되는 프로토콜에 필요한 만큼 많거나 적은 타입의 값을 이해할 수 있다. 이러한 제한의 부재는 CBOR가 극도로 제약된 환경에서 사용될 수 있게 한다.¶
이 섹션의 나머지는 CBOR 기반 프로토콜을 만들 때의 몇 가지 고려 사항을 논의한다. 몇 가지 예외를 제외하면, 이는 권고적일 뿐이며 BCP 14 [RFC2119] [RFC8174]의 의미에서 "MAY"로 해석될 수 있는 단어 이외의 BCP 14 언어를 명시적으로 제외한다. 예외들은 다양한 일반 및 애플리케이션별 인코더와 디코더를 모두 사용하면서 CBOR 기반 프로토콜의 상호 운용성을 촉진하는 것을 목표로 한다.¶
스트리밍 애플리케이션에서 데이터 스트림은 CBOR 데이터 항목들의 시퀀스를 연속으로 이어 붙인 것으로 구성될 수 있다. 이러한 환경에서는 이전 데이터 항목의 끝 이후에 데이터가 발견되면 디코더가 즉시 새 데이터 항목의 디코딩을 시작한다.¶
데이터 항목을 구성하는 모든 바이트가 디코더에 즉시 제공되지는 않을 수 있다. 일부 디코더는 완전한 데이터 항목을 애플리케이션에 제시할 수 있을 때까지 추가 데이터를 버퍼링한다. 다른 디코더는 최상위 데이터 항목에 대한 부분 정보를 애플리케이션에 제시할 수 있다. 예를 들어 이미 디코딩할 수 있는 중첩 데이터 항목이나, 아직 완전히 도착하지 않은 바이트 문자열의 일부도 제시할 수 있다. 그러한 애플리케이션은 또한 애플리케이션에 제시되는 점진적 데이터에 대해 원하는 보호를 제공할 수 있는, 일치하는 스트리밍 보안 메커니즘을 가져야 MUST 한다.¶
일부 애플리케이션과 프로토콜은 부정 길이 인코딩을 사용하고 싶어 하지 않을 수 있음에 유의한다. 부정 길이 인코딩을 사용하면 인코더가 개수를 세기 위해 모든 데이터를 마샬링할 필요가 없지만, 디코더는 항목의 끝을 기다리는 동안 증가하는 양의 메모리를 할당해야 한다. 이는 일부 애플리케이션에는 괜찮을 수 있지만 다른 애플리케이션에는 그렇지 않을 수 있다.¶
일반 CBOR 디코더는 모든 올바른 형식의 인코딩된 CBOR 데이터 항목을 디코딩하고 그 데이터 항목을 애플리케이션에 제시할 수 있다. 부록 C를 참조한다. (진단 표기법(섹션 8)은 올바른 형식의 CBOR 값을 사람에게 제시하는 데 사용될 수 있다.)¶
일반 CBOR 인코더는 인코더가 알지 못하는 단순 값과 태그를 포함하여, 애플리케이션이 올바른 형식의 어떤 값이든 CBOR 데이터 항목으로 인코딩하도록 지정할 수 있는 애플리케이션 인터페이스를 제공한다.¶
CBOR가 이러한 경우를 최소화하려고 시도하더라도,
모든 올바른 형식의 CBOR 데이터가 유효한 것은 아니다. 예를 들어,
인코딩된 텍스트 문자열 0x62c0ae는 유효한 UTF-8을 포함하지 않는다
([RFC3629]가 항상 가장 짧은
형식을 사용하도록 요구하기 때문). 따라서 이는 유효한 CBOR 항목이 아니다.
또한 특정 태그는 의미적 제약을 만들 수 있으며, 예를 들어
큰 수 태그가 다른 태그를 둘러싸거나, 태그 번호 0의 인스턴스가 바이트
문자열을 포함하거나 [RFC3339]의
date-time 생성 규칙과 일치하지 않는 내용을 가진 텍스트 문자열을 포함하는 경우
이러한 제약이 위반될 수 있다.
일반 인코더와 디코더가 유효하지 않은 데이터 처리를 가능하게 하기 위해
애플리케이션 인터페이스에 부자연스러운 선택을 해야 한다는
요구 사항은 없다. 일반 인코더와 디코더는
인코더/디코더가 작성된 시점에 특정 코드포인트가 등록되어 있지 않더라도
단순 값과 태그를 전달할 것으로 기대된다
(섹션 5.4).¶
올바른 형식이지만 유효하지 않은 CBOR 데이터 항목(섹션 1.2)은 그 안에 인코딩된 데이터를 CBOR 데이터 모델에서 해석하는 데 문제를 제기한다. CBOR 기반 프로토콜은 여러 계층으로 지정될 수 있으며, 이때 하위 계층은 자신들이 전달하는 일부 CBOR 데이터의 의미를 처리하지 않는다. 이러한 계층은 처리하지 않는 데이터의 유효성 오류를 알아차릴 수 없으며, 그 데이터를 있는 그대로 전달해야 MUST 한다. 유효하지 않은 CBOR 항목의 의미를 처리하는 첫 번째 계층은 두 가지 선택지 중 하나를 선택해야 MUST 한다.¶
CBOR 기반 프로토콜은 자신들의 디코더가 마주칠 수 있는 각 종류의 유효하지 않은 항목에 대해 이러한 옵션 중 어느 것을 취하는지 지정해야 MUST 한다.¶
이러한 문제는 CBOR의 기본 유효성 수준이나 태그(태그 유효성)의 맥락에서 발생할 수 있다.¶
기본 일반 데이터 모델에서는 두 종류의 유효성 오류가 발생할 수 있다.¶
기본 일반 데이터 모델에 태그를 추가함으로써 두 가지 추가적인 유효성 오류가 도입된다.¶
유효성 검사를 수행하는 디코더는 유효성 오류가 있는 데이터 항목을 신뢰성 있게 감지하기 위해 노력을 들인다. 예를 들어, 그러한 디코더는 이전 하위 섹션에 나열된 유효성 오류 중 어느 것이든 포함하는 CBOR 데이터 항목에 대해 오류를 보고하고 데이터를 반환하지 않는 API를 가져야 한다.¶
"Concise Binary Object Representation (CBOR) Tags" 레지스트리(섹션 9.2)에 정의된 태그 집합과 "Concise Binary Object Representation (CBOR) Simple Values" 레지스트리(섹션 9.1)에 정의된 단순 값 집합은 일반 디코더가 이해하는 집합을 넘어 언제든지 증가할 수 있다. 유효성 검사 디코더는 자신이 인식하지 못하는 그러한 경우를 만나면 다음 두 가지 중 하나를 수행할 수 있다.¶
후자의 접근 방식은 유효성 검사를 지원하지 않는 디코더에도 적합하며, 새로 등록된 태그와 단순 값에 대해 호출 애플리케이션과 동시에 인코더를 업데이트해야 할 필요 없이 전방 호환성을 제공한다. (이를 위해 디코더의 API는 호출 애플리케이션이 프로그램에 적합한 방식으로 처리할 수 있도록 알 수 없는 항목을 표시하는 능력이 필요하다.)¶
유효성 검사에 필요한 처리 중 일부는 상당한 비용을 가질 수 있으므로(특히 맵의 중복 감지), 유효성 검사 지원은 모든 CBOR 디코더에 부과되는 요구 사항이 아니다.¶
일부 인코더는 애플리케이션이 유효한 CBOR가 인코더에서 나오도록 입력 데이터를 제공한다고 가정한다. 일반 인코더는 또한 애플리케이션이 실제로 API에 부합하는 데이터를 제공하는지 여부와 무관하게 자신의 출력을 유효한 CBOR로 신뢰성 있게 제한하는 유효성 검사 모드를 제공하고자 할 수 있다.¶
CBOR 기반 프로토콜은 서로 다른 언어 환경이 표현 가능한 숫자의 범위와 정밀도에 서로 다른 제한을 부과한다는 점을 고려해야 한다. 예를 들어, 기본 JavaScript 숫자 시스템은 모든 숫자를 부동소수점 값으로 취급하므로, 53개를 초과하는 유효 비트를 가진 정수를 디코딩할 때 정밀도가 조용히 손실될 수 있다. 또 다른 예는 CBOR가 정수 표현의 부호 비트를 주요 타입에 보관하므로, 특정 길이의 부호 있는 숫자에 대해 동일한 길이의 일반적인 플랫폼 부호 있는 정수 표현보다 한 비트가 더 많다는 것이다 (예: 1+8바이트 정수의 경우 -264..264-1, 8바이트 int64_t의 경우 -263..263-1). 숫자를 사용하는 프로토콜은 디코더와 수신 애플리케이션에서 비사소한 숫자를 어떻게 처리할지에 대한 기대를 정의해야 한다.¶
부동소수점 수를 포함하는 CBOR 기반 프로토콜은 세 가지 형식(반정밀도, 단정밀도, 배정밀도) 중 어느 것이 지원되어야 하는지를 제한할 수 있다. 정수 전용 애플리케이션의 경우, 프로토콜은 부동소수점 값의 사용을 완전히 배제하고자 할 수 있다.¶
간결성을 위해 설계된 CBOR 기반 프로토콜은 애플리케이션에 필요한 것보다 긴 특정 정수 인코딩을 배제하여, 예를 들어 64비트 정수를 구현할 필요를 줄이고자 할 수 있다. 인코더가 주어진 값을 표현할 수 있는 가장 간결한 정수 표현을 사용할 것이라는 기대가 있다. 그러나 결정적 인코딩을 요구하지 않는 간결한 애플리케이션은 주어진 크기의 정수를 디코딩할 수 있는 한, 필요한 것보다 긴 인코딩(예: "0"을 0b000_11001 뒤에 두 바이트 0x00이 오는 방식으로 인코딩)을 사용하는 값을 받아들여야 한다. 유사한 고려 사항은 부동소수점 값에도 적용된다. 선호 직렬화와 필요한 것보다 긴 직렬화를 모두 디코딩하는 것이 권장된다.¶
특정 숫자를 정수로 표현할지, 또는 십진 분수나 큰 부동소수점 수로 표현할지 선택지를 제공하는 제약 애플리케이션용 CBOR 기반 프로토콜(예: 지수가 작고 음이 아닌 경우)은 정수 표현이 직접 사용된다는 구현 품질 기대를 표현하고자 할 수 있다.¶
인코딩 및 디코딩 애플리케이션은 맵에서 어떤 타입의 키가 사용될 것인지에 대해 합의해야 한다. JSON 기반 애플리케이션과 상호 운용해야 하는 애플리케이션에서는 키를 텍스트 문자열로만 제한함으로써 변환이 단순해진다. 그렇지 않으면 다른 CBOR 타입에서 텍스트 문자열로의 지정된 매핑이 있어야 하며, 이는 종종 구현 오류로 이어진다. 키가 본질적으로 숫자인 애플리케이션에서, 그리고 키의 숫자 순서가 애플리케이션에 중요하다면, 키에 숫자를 직접 사용하는 것이 유용하다.¶
여러 타입의 키가 사용될 경우, 사용될 특정 프로그래밍 환경에서 이러한 타입들이 어떻게 표현될지를 고려해야 한다. 예를 들어, JavaScript Maps [ECMA262]에서는 정수 1인 키를 부동소수점 1.0인 키와 구별할 수 없다. 이는 정수 키가 사용된다면 프로토콜이 같은 맵에서 값이 우연히 정수인 부동소수점 키의 사용을 피해야 함을 의미한다.¶
CBOR 데이터 항목 안에 중첩된 데이터 항목을 디코딩하는 즉시 전달하는 디코더("스트리밍 디코더")는 종종 맵에서 키의 고유성을 확인하는 데 필요한 상태를 유지하지 않는다. 마찬가지로, 포함하는 데이터 항목이 완전히 사용 가능해지기 전에 데이터 항목의 인코딩을 시작할 수 있는 인코더("스트리밍 인코더")는 데이터 소스가 고유성을 유지한다고 믿음으로써 자신의 오버헤드를 크게 줄이고자 할 수 있다.¶
CBOR 기반 프로토콜은 수신 애플리케이션이 맵에서 여러 동일한 키를 보았을 때 무엇을 해야 하는지 정의해야 MUST 한다. 프로토콜의 결과 규칙은 CBOR 데이터 모델을 존중해야 MUST 한다. 즉, 동일한 키를 가진 항목에 대한 특정 처리를 규정할 수 없으며, 다만 맵에 동일한 키가 있으면 잘못된 형식의 맵을 나타내고 디코더가 오류로 중지해야 한다는 규칙을 둘 수는 있다. 중복 키를 가진 항목을 보이는 맵을 처리할 때, 일반 디코더는 다음 중 하나를 수행할 수 있다.¶
일반 디코더는 이 세 접근 방식 중 어느 것을 구현하는지 문서화해야 한다.¶
맵에 대한 CBOR 데이터 모델은 맵 표현에서 키/값 쌍의 순서에 의미를 부여하는 것을 허용하지 않는다. 따라서 CBOR 기반 프로토콜은 맵에서 키/값 쌍의 순서를 바꾸는 것이 의미를 바꾼다고 지정해서는 MUST NOT 안 된다. 다만 예를 들어 결정적 인코딩(섹션 4.2)의 요구 사항을 충족하지 않는 순서를 허용하지 않는다고 지정하는 것은 예외이다. (맵 순서가 타이밍, 캐시 사용 및 기타 잠재적 부채널에 미치는 2차 효과는 의미의 일부로 간주되지 않지만, 프로토콜이 결정적 인코딩 형식을 요구할 충분한 이유가 될 수는 있다.)¶
제약 장치용 애플리케이션은 자주 사용되는 키가 적은 수로 있는 맵을 가진 경우, 작은 정수를 키로 사용하는 것을 고려해야 한다. 예를 들어 24개 이하의 키 집합은 부호 없는 정수로 한 바이트에 인코딩될 수 있으며, 음의 정수도 사용한다면 최대 48개까지 가능하다. 덜 자주 발생하는 키는 더 긴 인코딩을 가진 정수를 사용할 수 있다.¶
CBOR 데이터 항목에 적용되는 특정 데이터 모델은 맵에 나타나는 키가 중복인지 서로 다른지를 결정하는 데 사용된다.¶
일반 데이터 모델 수준에서, 수치적으로 동등한 정수와 부동소수점 값은 서로 구별되며, 다양한 큰 숫자(태그 2부터 5까지)와도 구별된다. 마찬가지로, 텍스트 문자열은 같은 바이트로 구성되어 있더라도 바이트 문자열과 구별된다. 태그가 지정된 값은 태그가 없는 값이나 다른 태그 번호로 태그가 지정된 값과 구별된다.¶
이러한 각 그룹 안에서, 숫자 값은 수치적으로 같지 않으면 서로 구별된다(특히 -0.0은 0.0과 같다). 맵 키 동등성의 목적상, NaN 값은 두 가수를 오른쪽에서 64비트까지 0으로 확장한 뒤 같은 가수를 가지면 동등하다.¶
바이트 문자열과 텍스트 문자열은 모두 바이트 단위로 비교되고, 배열은 요소 단위로 비교되며, 같은 수의 바이트/요소와 같은 위치의 같은 값을 가지면 같다. 두 맵은 순서와 관계없이 같은 쌍 집합을 가지면 같다. 쌍은 키와 값이 모두 같으면 같다.¶
태그가 지정된 값은 태그 번호와 태그 내용이 모두 같으면 같다. (특정 태그에 대한 처리를 제공하는 일반 디코더는 예를 들어 태그 2 또는 태그 3의 내용에 선행 0이 있는 경우처럼 일부 의미적으로 동등한 값을 구별하지 못할 수도 있음에 유의한다 (섹션 3.4.3).) 단순 값은 단순히 같은 값을 가지면 같다. 일반 데이터 모델에서는 그 밖의 것은 아무것도 같지 않다. 단순 값 2는 정수 2와 동등하지 않으며, 배열은 결코 맵과 동등하지 않다.¶
섹션 2.2에서 논의한 것처럼, 특정 데이터 모델은 일반 데이터 모델에서는 서로 다른 값들을 맵 키 비교 목적상 동등하게 만들 수 있다. 이는 일반 디코더가 애플리케이션에 디코딩된 맵을 전달할 수 있으며, 그 애플리케이션이 중복 맵 키를 검사해야 함을 의미한다는 점에 유의한다 (또는 디코더가 애플리케이션을 위해 이 서비스를 수행하는 프로그래밍 인터페이스를 제공할 수 있다). 특정 데이터 모델은 일반 데이터 모델 수준에서 이 목적상 같은 맵 키 값을 구별할 수 없다.¶
이 섹션은 CBOR와 JSON 간 변환에 대한 비규범적 조언을 제공한다. 변환기 구현은 여기의 조언 중 원하는 것을 MAY 사용할 수 있다.¶
JSON 텍스트는 인코딩된 바이트 시퀀스가 아니라 문자 시퀀스인 반면, CBOR 데이터 항목은 문자가 아니라 바이트로 구성된다는 점에 주목할 가치가 있다.¶
CBOR의 대부분 타입은 JSON에 직접적인 대응물이 있다. 그러나 일부는 그렇지 않으며, CBOR-to-JSON 변환기를 구현하는 사람은 그런 경우 무엇을 할지 고려해야 한다. 다음 비규범적 조언은 이들을 JSON null과 같은 단일 대체 값으로 변환하는 방식으로 다룬다.¶
CBOR-to-JSON 변환기는 상호 운용성을 극대화하고 JSON 출력이 예측 가능한 결과로 처리될 수 있다는 신뢰를 높이기 위해 JSON 프로필 I-JSON [RFC7493]을 따르고자 할 수 있다. 예를 들어, 이는 안정적으로 표현될 수 있는 정수 범위뿐 아니라, 오래된 JSON 구현이 지원할 수 있는 최상위 항목에도 영향을 미친다.¶
모든 JSON 값은 일단 디코딩되면 하나 이상의 CBOR 값으로 직접 매핑된다. 어떤 종류의 CBOR 생성에서와 마찬가지로, 숫자 표현과 관련하여 결정을 내려야 한다. 제안되는 변환에서는 다음과 같다.¶
CBOR는 일반적으로 JSON보다 더 간결한 인코딩을 제공하도록 설계되었다. 떠올릴 수 있는 한 가지 구현 전략은 단일 버퍼 안에서 JSON-to-CBOR 인코딩을 제자리에서 수행하는 것이다. 이 전략은 병적인 여러 경우를 신중하게 고려해야 한다. 예를 들어, 이스케이프가 없거나 매우 적고 255바이트보다 길거나 훨씬 긴 일부 문자열은 CBOR에서 UTF-8 문자열로 인코딩될 때 확장될 수 있다. 마찬가지로, 일부 이진 부동소수점 표현은 JSON의 짧은 십진 표현(1.1, 1e9)에서 확장을 일으킬 수 있다. 이를 올바르게 처리하기는 어려울 수 있으며, 그 결과 발생하는 취약점은 공격자에 의해 악용될 수 있다.¶
성공적인 프로토콜은 시간이 지나면서 발전한다. 새로운 아이디어가 나타나고, 구현 플랫폼이 개선되며, 관련 프로토콜이 개발되고 발전하고, 애플리케이션과 프로토콜의 새로운 요구 사항이 추가된다. 따라서 프로토콜 발전을 촉진하는 것은 모든 프로토콜 개발에서 중요한 설계 고려 사항이다.¶
CBOR를 사용할 프로토콜을 위해, CBOR는 그 발전을 촉진하는 유용한 메커니즘을 제공한다. 이를 위한 모범 사례는 잘 알려져 있으며, 특히 JSON 기반 프로토콜의 JSON 형식 개발에서 알려져 있다. 따라서 그러한 모범 사례는 이 명세의 범위 밖이다.¶
그러나 CBOR 자체의 발전을 촉진하는 것은 그 범위 안에 매우 잘 들어맞는다. CBOR는 CBOR 기반 프로토콜 개발을 위한 안정적인 기반을 제공하면서도 발전할 수 있도록 설계되었다. 성공적인 프로토콜은 수십 년 동안 살아남을 수 있으므로, CBOR는 수십 년 동안 사용되고 발전하도록 설계되어야 한다. 이 섹션은 CBOR의 발전에 대한 몇 가지 지침을 제공한다. 이는 이 문서의 다른 부분보다 필연적으로 더 주관적이다. 또한 프로토콜 개발에 관한 교과서가 되지 않도록 필연적으로 불완전하다.¶
프로토콜 설계에서 발전의 기회는 종종 확장 지점의 형태로 포함된다. 예를 들어, 처음부터 완전히 할당되지 않은 코드포인트 공간이 있을 수 있으며, 프로토콜은 처음 할당된 것보다 더 많은 코드포인트를 사용하기 시작하는 구현을 용인하고 수용하도록 설계된다.¶
필요한 범위를 예측하기 어려울 수 있으므로 코드포인트 공간의 크기를 정하는 것은 어려울 수 있다. 프로토콜 설계는 의도된 프로토콜 수명 동안 천천히 채워질 수 있을 만큼 코드포인트 공간을 충분히 크게 만들도록 시도해야 한다.¶
CBOR에는 세 가지 주요 확장 지점이 있다.¶
인간의 마음은 때때로 어떤 것을 깔끔하게 만들기 위해 작게 인식되는 빈틈을 채우는 데 끌린다. 추가 정보 값의 코드포인트 공간에 남아 있는 빈틈은, 단지 거기에 있다는 이유만으로 새로운 아이디어를 끌어들이는 요인이 될 것으로 예상한다.¶
현재 명세는 추가 정보 코드포인트 공간을 IANA 레지스트리로 관리하지 않는다. 대신, 이 공간에서의 할당은 이 명세를 갱신하는 방법으로만 수행될 수 있다.¶
n >= 24인 추가 정보 값의 경우, 추가 데이터의 크기는 일반적으로 2n-24바이트이다. 따라서 추가 정보 값 28과 29는 프로토콜에 추가해야 할 필요가 생길 경우 128비트 및 256비트 수량의 후보로 보아야 한다. 그러면 추가 정보 값 30은 일반 할당에 사용할 수 있는 유일한 추가 정보 값이 되며, 현재 명세의 갱신을 통해 이를 할당하기 전에 매우 좋은 이유가 있어야 한다.¶
CBOR는 이진 교환 형식이다. 문서화와 디버깅을 촉진하고, 특히 디버깅에서 협력하는 엔터티 간의 소통을 촉진하기 위해, 이 섹션은 단순한 사람이 읽을 수 있는 진단 표기법을 정의한다. 실제 교환은 항상 이진 형식에서 일어난다.¶
이는 실제로 진단 형식이며, 구문 분석되도록 의도되지 않았다는 점에 유의한다. 따라서 이 문서에는 (ABNF와 같은) 공식 정의가 제공되지 않는다. (구성 파일에서 CBOR 데이터 항목을 표현하기 위한 텍스트 기반 형식을 찾는 구현자는 YAML [YAML]도 고려하고자 할 수 있다.)¶
진단 표기법은 RFC 8259에 정의된 JSON을 느슨하게 기반으로 하며, 필요한 곳에서 확장한다.¶
이 표기법은 숫자(정수 및 부동소수점), True(>true<), False(>false<), Null(>null<), UTF-8 문자열, 배열 및 맵에 대한 JSON 구문을 차용한다(맵은 JSON에서 객체라고 불린다. 진단 표기법은 여기서 키 위치에 어떤 데이터 항목도 허용하여 JSON을 확장한다). Undefined는 JavaScript에서처럼 >undefined<로 쓴다. 비유한 부동소수점 수 Infinity, -Infinity 및 NaN은 이 문장에 있는 그대로 정확히 쓴다(이는 JSON이 허용하지 않지만 JavaScript에서 쓸 수 있는 방식이기도 하다). 태그는 태그 번호에 대한 정수 숫자와, 그 뒤의 괄호 안 태그 내용으로 쓴다. 예를 들어, RFC 3339(ISO 8601)가 지정한 형식의 날짜는 다음과 같이 표기될 수 있다.¶
0("2013-03-21T20:04:00Z")¶
또는 동등한 상대 시간은 다음과 같다.¶
1(1363896240)¶
바이트 문자열은 base 인코딩 중 하나로 표기되며, 패딩 없이 작은따옴표로 둘러싸고, base16의 경우 >h<, base32의 경우 >b32<, base32hex의 경우 >h32<, base64 또는 base64url의 경우 >b64<를 앞에 붙인다 (실제 인코딩은 서로 겹치지 않으므로 문자열은 모호하지 않다). 예를 들어, 바이트 문자열 0x12345678은 h'12345678', b32'CI2FM6A' 또는 b64'EjRWeA'로 쓸 수 있다.¶
할당되지 않은 단순 값은 괄호 안에 적절한 정수를 넣어 "simple()"로 제공된다. 예를 들어, "simple(42)"는 주요 타입 7, 값 42를 나타낸다.¶
여기에 정의된 진단 표기법에 대한 여러 유용한 확장은 [RFC8610]의 부록 G, "Extended Diagnostic Notation" (EDN)에 제공되어 있다. 마찬가지로, 이 표기법은 이 문서에서 다루지 않는 NaN 페이로드에 대한 문서화를 제공하기 위해 별도 문서에서 확장될 수 있다.¶
때때로 진단 표기법에서 여러 대체 표현 중 실제로 어떤 것이 사용되었는지를 나타내는 것이 유용하다. 예를 들어, 진단 디코더가 >1.5<로 쓴 데이터 항목은 반정밀도, 단정밀도 또는 배정밀도 부동소수점으로 인코딩되었을 수 있다.¶
인코딩 표시자의 관례는
밑줄로 시작하고 뒤따르는 모든 영숫자 또는 밑줄 문자가
인코딩 표시자라는 것이며, 이 정보에 관심이 없는 사람은
이를 무시할 수 있다. 예: _ 또는 _3.
인코딩 표시자는 항상
선택 사항이다.¶
맵의 여는 중괄호나 배열의 여는 대괄호 뒤에 단일 밑줄을 써서 데이터 항목이 부정 길이 형식으로 표현되었음을 나타낼 수 있다. 예를 들어, [_ 1, 2]는 데이터 항목 [1, 2]를 표현하는 데 부정 길이 표현이 사용되었다는 표시자를 포함한다.¶
밑줄 뒤에 십진 숫자 n이 오면 앞선 항목(또는 배열과 맵의 경우 앞선 대괄호나 중괄호로 시작하는 항목)이 24+n의 추가 정보 값으로 인코딩되었음을 나타낸다. 예를 들어, 1.5_1은 반정밀도 부동소수점 수이고, 1.5_3은 배정밀도로 인코딩된다. 이 인코딩 표시자는 부록 A에는 표시되지 않는다. (따라서 인코딩 표시자 "_"는 사용되지 않는 전체 형식 "_7"의 축약이라는 점에 유의한다.)¶
부정 길이의 바이트 및 텍스트 문자열의 자세한 청크 구조는 (_ h'0123', h'4567') 및 (_ "foo", "bar") 형식으로 표기할 수 있다. 그러나 내부에 청크가 없는 부정 길이 문자열의 경우, (_ )는 바이트 문자열(0x5fff)을 의미하는지 텍스트 문자열 (0x7fff)을 의미하는지 모호하므로 사용되지 않는다. 대신 기본 형식 ''_ 및 ""_를 사용할 수 있으며, 청크가 없는 경우에만 예약된다. 이는 청크 구조를 보존하기 위해 (_ ''), (_ "") 등으로 표기해야 하는, 빈 청크만 있는(허용되지만 실제로는 유용하지 않은) 인코딩의 짧은 형식이 아니다.¶
IANA는 새로운 CBOR 값을 위해 두 개의 레지스트리를 만들었다. 이 레지스트리들은 별도이며, 즉 포괄 레지스트리 아래에 있지 않고, [RFC8126]의 규칙을 따른다. IANA는 또한 새 미디어 타입, 관련 CoAP Content-Format 항목 및 구조화 구문 접미사를 할당했다.¶
IANA는 [IANA.cbor-simple-values]에 "Concise Binary Object Representation (CBOR) Simple Values" 레지스트리를 만들었다. 초기 값은 표 4에 나와 있다.¶
0부터 19까지 범위의 새 항목은 Standards Action [RFC8126]으로 할당된다. 하위 번호를 연속 블록(있는 경우)을 위해 예약하기 위해, IANA가 숫자 16부터 값을 할당하는 것이 제안된다.¶
32부터 255까지 범위의 새 항목은 Specification Required로 할당된다.¶
단일 인코딩된 CBOR 데이터 항목에 대한 인터넷 미디어 타입 [RFC6838] ("MIME 타입")은 "Media Types" 레지스트리 [IANA.media-types]에 정의된 "application/cbor"이다:¶
CBOR용 CoAP Content-Format은 "Constrained RESTful Environments (CoRE) Parameters" 레지스트리 [IANA.core-parameters] 내의 "CoAP Content-Formats" 하위 레지스트리에 등록되었다:¶
단일 인코딩된 CBOR 데이터 항목을 기반으로 하는 미디어 타입에 대한 구조화 구문 접미사 [RFC6838]는 +cbor이며, IANA는 이를 "Structured Syntax Suffixes" 레지스트리 [IANA.structured-suffix]에 등록했다:¶
+cbor에 대해 지정된 프래그먼트 식별자의 구문과 의미는 "application/cbor"에 대해 지정된 것과 같아야 SHOULD 한다. (RFC 8949 출판 시점에는 "application/cbor"에 대해 정의된 프래그먼트 식별 구문이 없다.)¶
특정 "xxx/yyy+cbor"에 대한 프래그먼트 식별자의 구문과 의미는 다음과 같이 처리되어야 SHOULD 한다:¶
네트워크에 노출된 애플리케이션은 들어오는 데이터에 대한 처리 로직에서 취약점을 보일 수 있다. 복잡한 파서는 노드를 원격으로 크래시시키거나, 심지어 그 노드에서 임의 코드를 원격으로 실행할 수 있는 능력과 같은 취약점의 유력한 원천으로 잘 알려져 있다. CBOR는 가능한 경우 인코딩 가능한 값 전체 범위에 의미를 부여하여 파서 복잡성을 줄임으로써, 그러한 취약점을 도입할 기회를 좁히려고 시도한다.¶
CBOR 디코더는 검증되지 않은 입력을 처리하는 첫 단계로 자주 사용되므로, CBOR 데이터 항목을 디코딩하는 시스템을 손상시키거나, 넘치게 하거나, 제어를 획득하도록 설계될 수 있는 모든 유형의 적대적 입력에 완전히 대비해야 한다. CBOR 디코더는 모든 입력이 방화벽에서 검사되었거나, TLS와 같은 보안 채널을 통해 왔거나, 암호화 또는 서명되었거나, 신뢰된다고 추정되는 다른 출처에서 왔더라도 적대적일 수 있다고 가정해야 한다.¶
섹션 4.1은 비선호 직렬화를 사용하는 CBOR 인코더의 입력과 함께 제약 CBOR 디코더를 사용할 때 상호 운용성의 한계에 대한 예를 제공한다. 단일 데이터 항목이 그러한 제약 디코더와 완전한 디코더 모두에서 소비되는 경우, 콘텐츠를 주입하거나 조작할 수 있는 공격자가 악용할 수 있는 보안 문제로 이어질 수 있다.¶
이 문서 전반에서 논의한 것처럼, 어떤 상황에서는 "동등"하고 다른 상황에서는 "동등하지 않음"으로 간주될 수 있는 값이 많다. 단 하나의 예로, 숫자 "one"에 대한 수치 값은 정수 또는 큰 수로 표현될 수 있다. CBOR 입력을 해석하는 시스템은 숫자 "one"에 대해 두 형식 중 어느 것이든 받아들일 수도 있고, 한 형식(또는 두 형식 모두)을 거부할 수도 있다. 그러한 수용 또는 거부는 해석된 입력을 사용하는 프로그램에서 보안상의 영향을 가질 수 있다.¶
적대적 입력은 버퍼를 넘치게 하거나, 정수 산술에서 오버플로 또는 언더플로를 일으키거나, 다른 디코딩 교란을 유발하도록 구성될 수 있다. CBOR 데이터 항목은 의도적으로 극도로 크거나 너무 짧은 길이나 크기를 가질 수 있다. 리소스 고갈 공격은 디코더가 매우 큰 데이터 항목 (문자열, 배열, 맵, 또는 임의 정밀도 숫자까지)을 할당하도록 유인하거나, 깊게 중첩된 항목을 설정하여 스택 깊이를 고갈시키려고 시도할 수 있다. 디코더는 이러한 공격을 완화하기 위해 적절한 리소스 관리를 가져야 한다. (매우 큰 크기가 주어진 항목은 정수 오버플로 취약점을 악용하려고 시도할 수도 있다.)¶
CBOR 디코더는 정의상 올바른 형식의 CBOR만 받아들이며, 이것이 견고성의 첫 단계이다. 올바른 형식의 CBOR가 아닌 입력은 올바른 형식이 아님이 감지된 지점부터 더 이상의 처리를 유발하지 않는다. 가능하다면, 이 지점까지 디코딩된 어떤 데이터도 CBOR 디코더를 사용하는 애플리케이션에 영향을 주지 않아야 한다.¶
올바른 형식임을 확인하는 것에 더하여, CBOR 디코더는 CBOR 데이터에 대한 유효성 검사도 수행할 수 있다. 또는 그러한 검사를 디코더를 사용하는 애플리케이션에 맡길 수 있다. 이 선택은 디코더에 명확히 문서화되어야 한다. CBOR 수준의 유효성을 넘어, 애플리케이션은 입력이 CBOR로 직렬화된 애플리케이션 프로토콜과 일치하는지도 확인해야 한다.¶
입력 검사 자체가 리소스를 소비할 수 있다. 이는 보통 입력 크기에 선형적이므로, 공격자는 입력 검증에 방어자가 소비하는 리소스와 상응하는 리소스를 소비해야 함을 의미한다. 그러나 공격자는 자신이 생성하는 것보다 대상 디코더가 처리하는 데 더 오래 걸리는 입력을 만들 수 있을 수도 있다. 임의 정밀도 숫자 처리는 선형 노력을 초과할 수 있다. 또한 디코더가 맵의 메모리 내 표현을 구축하는 데 사용하는 일부 해시 테이블 구현은, 비밀 키 ([SIPHASH_LNCS]의 섹션 7 참조, 또한 [SIPHASH_OPEN])나 다른 완화책이 사용되지 않으면 이차적 노력을 소비하도록 공격받을 수 있다. 이러한 초선형 노력은 공격자가 입력 검증기에서 또는 그 이전에 리소스를 고갈시키는 데 악용될 수 있으므로, CBOR 디코더 구현에서 피해야 한다. 태그 번호 정의와 그 구현은 이러한 종류의 보안 고려 사항을 추가할 수 있다는 점에 유의한다. 그러한 경우 이는 태그 번호 정의의 보안 고려 사항에서 논의되어야 한다.¶
CBOR 인코더는 네트워크에서 직접 입력을 받지 않으므로 CBOR 디코더와 같은 방식으로 직접 공격받지는 않는다. 그러나 CBOR 인코더는 구현의 다른 수준에서 입력을 받는 API를 가지고 있는 경우가 많으며, 그 API를 통해 공격받을 수 있다. 그 API의 설계와 구현은 호출자의 동작이 적대적 입력이나 코딩 실수에 기반할 수 있다고 가정해야 한다. 이는 버퍼 오버런, 정수 산술의 오버플로와 언더플로, 그리고 인코더를 교란하려는 기타 오류에 대해 입력을 검사해야 한다.¶
프로토콜은 잠재적인 여러 해석이 신뢰성 있게 단일 해석으로 줄어들도록 정의되어야 한다. 예를 들어, 공격자는 맵의 중복 키와 같은 유효하지 않은 입력을 사용하거나, 숫자 처리의 정밀도 차이를 악용하여 한 애플리케이션이 두 번째 애플리케이션에서 사용될 해석과 다른 해석을 기반으로 결정을 내리게 할 수 있다. 일관된 해석을 촉진하기 위해, 인코더와 디코더 구현은 유효성 검사 동작 모드 (섹션 5.4)를 제공해야 한다. 그러나 일반 디코더는 애플리케이션이 입력 데이터에 부과하는 모든 요구 사항을 알 수 없으므로, 애플리케이션이 자체 입력 검사를 수행할 책임을 덜어 주지는 않는다는 점에 유의한다. 또한 정의된 태그 번호 집합은 발전하므로, 애플리케이션은 자신이 사용하는 일반 디코더가 아직 유효성 검사를 지원하지 않는 태그 번호를 사용할 수 있다. 따라서 일반 디코더는 어떤 태그 번호를 지원하는지와, 그 태그 번호들 및 기본 CBOR(UTF-8 검사, 중복 맵 키 검사)에 대해 어떤 유효성 검사를 제공하는지를 문서화해야 한다.¶
섹션 3.4.3은 숫자를 인코딩할 때 기본 정수 대신 큰 수 표현을 사용하는 비선호 선택이 애플리케이션 의미를 갖도록 의도되지 않았다고 언급한다. 그러나 CBOR 데이터를 수신하는 애플리케이션이 기본 일반 데이터 모델의 디코더를 사용하는 경우 그러한 의미를 가질 수 있다. 두 의미 집합이 다르면 이 불일치는 보안 문제를 일으킨다. 따라서 CBOR를 사용하는 애플리케이션은 CBOR 데이터의 각 사용에 대해 자신들이 사용하는 데이터 모델을 지정해야 한다.¶
CBOR 데이터를 다른 형식으로 변환하는 것은 흔하다. 많은 경우, CBOR는 다른 형식보다 더 표현력 있는 타입을 가진다. 이는 특히 JSON으로의 일반적인 변환에서 참이다. 타입 정보의 손실은 표현력이 더 낮은 데이터를 처리하는 시스템에 보안 문제를 일으킬 수 있다.¶
섹션 6.2는 공격자가 애플리케이션이 변환을 수행하고 있음을 알고 있다면 공격을 허용할 수 있는, CBOR와 JSON 간 변환의 가능한 일반적 사용 시나리오를 설명한다.¶
[RFC4648]의 base16 및 base64 사용에 대한 보안 고려 사항과, [RFC3629]의 UTF-8 사용에 대한 보안 고려 사항은 CBOR에도 관련된다.¶
다음 표는 일부 CBOR 인코딩 값을 16진수 (오른쪽 열)로 제공하며, 이 값들에 대한 진단 표기법(왼쪽 열)도 함께 제공한다. 문자열 "\u00fc"는 단일 Unicode 문자 U+00FC (LATIN SMALL LETTER U WITH DIAERESIS, "ü")를 포함하는 UTF-8 문자열에 대한 진단 표기법의 한 형태임에 유의한다. 마찬가지로, "\u6c34"는 단일 문자 U+6C34 (CJK UNIFIED IDEOGRAPH-6C34, "水")를 가진 진단 표기법의 UTF-8 문자열로, 종종 "물"을 나타내며, "\ud800\udd51"은 단일 문자 U+10151 (GREEK ACROPHONIC ATTIC FIFTY STATERS, "𐅑")를 가진 진단 표기법의 UTF-8 문자열이다. (이러한 모든 단일 문자 문자열은 진단 표기법에서 네이티브 UTF-8로도 표현될 수 있지만, ASCII 전용 명세가 요구되는 경우에는 그렇지 않다는 점에 유의한다.) 큰 수에 대해 제공된 진단 표기법에서는, 의도된 수치 값이 태그가 지정된 바이트 문자열 (예: 2(h'010000000000000000')) 대신 십진수 숫자 (예: 18446744073709551616)로 표시된다.¶
| 진단 | 인코딩 |
|---|---|
| 0 | 0x00 |
| 1 | 0x01 |
| 10 | 0x0a |
| 23 | 0x17 |
| 24 | 0x1818 |
| 25 | 0x1819 |
| 100 | 0x1864 |
| 1000 | 0x1903e8 |
| 1000000 | 0x1a000f4240 |
| 1000000000000 | 0x1b000000e8d4a51000 |
| 18446744073709551615 | 0x1bffffffffffffffff |
| 18446744073709551616 | 0xc249010000000000000000 |
| -18446744073709551616 | 0x3bffffffffffffffff |
| -18446744073709551617 | 0xc349010000000000000000 |
| -1 | 0x20 |
| -10 | 0x29 |
| -100 | 0x3863 |
| -1000 | 0x3903e7 |
| 0.0 | 0xf90000 |
| -0.0 | 0xf98000 |
| 1.0 | 0xf93c00 |
| 1.1 | 0xfb3ff199999999999a |
| 1.5 | 0xf93e00 |
| 65504.0 | 0xf97bff |
| 100000.0 | 0xfa47c35000 |
| 3.4028234663852886e+38 | 0xfa7f7fffff |
| 1.0e+300 | 0xfb7e37e43c8800759c |
| 5.960464477539063e-8 | 0xf90001 |
| 0.00006103515625 | 0xf90400 |
| -4.0 | 0xf9c400 |
| -4.1 | 0xfbc010666666666666 |
| Infinity | 0xf97c00 |
| NaN | 0xf97e00 |
| -Infinity | 0xf9fc00 |
| Infinity | 0xfa7f800000 |
| NaN | 0xfa7fc00000 |
| -Infinity | 0xfaff800000 |
| Infinity | 0xfb7ff0000000000000 |
| NaN | 0xfb7ff8000000000000 |
| -Infinity | 0xfbfff0000000000000 |
| false | 0xf4 |
| true | 0xf5 |
| null | 0xf6 |
| undefined | 0xf7 |
| simple(16) | 0xf0 |
| simple(255) | 0xf8ff |
| 0("2013-03-21T20:04:00Z") | 0xc074323031332d30332d32315432303a 30343a30305a |
| 1(1363896240) | 0xc11a514b67b0 |
| 1(1363896240.5) | 0xc1fb41d452d9ec200000 |
| 23(h'01020304') | 0xd74401020304 |
| 24(h'6449455446') | 0xd818456449455446 |
| 32("http://www.example.com") | 0xd82076687474703a2f2f7777772e6578 616d706c652e636f6d |
| h'' | 0x40 |
| h'01020304' | 0x4401020304 |
| "" | 0x60 |
| "a" | 0x6161 |
| "IETF" | 0x6449455446 |
| "\"\\" | 0x62225c |
| "\u00fc" | 0x62c3bc |
| "\u6c34" | 0x63e6b0b4 |
| "\ud800\udd51" | 0x64f0908591 |
| [] | 0x80 |
| [1, 2, 3] | 0x83010203 |
| [1, [2, 3], [4, 5]] | 0x8301820203820405 |
| [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] | 0x98190102030405060708090a0b0c0d0e 0f101112131415161718181819 |
| {} | 0xa0 |
| {1: 2, 3: 4} | 0xa201020304 |
| {"a": 1, "b": [2, 3]} | 0xa26161016162820203 |
| ["a", {"b": "c"}] | 0x826161a161626163 |
| {"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"} | 0xa5616161416162614261636143616461 4461656145 |
| (_ h'0102', h'030405') | 0x5f42010243030405ff |
| (_ "strea", "ming") | 0x7f657374726561646d696e67ff |
| [_ ] | 0x9fff |
| [_ 1, [2, 3], [_ 4, 5]] | 0x9f018202039f0405ffff |
| [_ 1, [2, 3], [4, 5]] | 0x9f01820203820405ff |
| [1, [2, 3], [_ 4, 5]] | 0x83018202039f0405ff |
| [1, [_ 2, 3], [4, 5]] | 0x83019f0203ff820405 |
| [_ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] | 0x9f0102030405060708090a0b0c0d0e0f 101112131415161718181819ff |
| {_ "a": 1, "b": [_ 2, 3]} | 0xbf61610161629f0203ffff |
| ["a", {_ "b": "c"}] | 0x826161bf61626163ff |
| {_ "Fun": true, "Amt": -2} | 0xbf6346756ef563416d7421ff |
간결성을 위해, 이 점프 테이블은 향후 확장을 위해 예약된 초기 바이트를 표시하지 않는다. 또한 선택 기능에 사용할 수 있는 초기 바이트 중 일부만 보여 준다. (모든 부호 없는 정수는 네트워크 바이트 순서이다.)¶
| 바이트 | 구조/의미 |
|---|---|
| 0x00..0x17 | 부호 없는 정수 0x00..0x17 (0..23) |
| 0x18 | 부호 없는 정수(1바이트 uint8_t가 뒤따름) |
| 0x19 | 부호 없는 정수(2바이트 uint16_t가 뒤따름) |
| 0x1a | 부호 없는 정수(4바이트 uint32_t가 뒤따름) |
| 0x1b | 부호 없는 정수(8바이트 uint64_t가 뒤따름) |
| 0x20..0x37 | 음의 정수 -1-0x00..-1-0x17 (-1..-24) |
| 0x38 | 음의 정수 -1-n(n에 대한 1바이트 uint8_t가 뒤따름) |
| 0x39 | 음의 정수 -1-n(n에 대한 2바이트 uint16_t가 뒤따름) |
| 0x3a | 음의 정수 -1-n(n에 대한 4바이트 uint32_t가 뒤따름) |
| 0x3b | 음의 정수 -1-n(n에 대한 8바이트 uint64_t가 뒤따름) |
| 0x40..0x57 | 바이트 문자열(0x00..0x17바이트가 뒤따름) |
| 0x58 | 바이트 문자열(n에 대한 1바이트 uint8_t와 그 뒤에 n바이트가 뒤따름) |
| 0x59 | 바이트 문자열(n에 대한 2바이트 uint16_t와 그 뒤에 n바이트가 뒤따름) |
| 0x5a | 바이트 문자열(n에 대한 4바이트 uint32_t와 그 뒤에 n바이트가 뒤따름) |
| 0x5b | 바이트 문자열(n에 대한 8바이트 uint64_t와 그 뒤에 n바이트가 뒤따름) |
| 0x5f | 바이트 문자열, 바이트 문자열들이 뒤따르며 "break"로 종료됨 |
| 0x60..0x77 | UTF-8 문자열(0x00..0x17바이트가 뒤따름) |
| 0x78 | UTF-8 문자열(n에 대한 1바이트 uint8_t와 그 뒤에 n바이트가 뒤따름) |
| 0x79 | UTF-8 문자열(n에 대한 2바이트 uint16_t와 그 뒤에 n바이트가 뒤따름) |
| 0x7a | UTF-8 문자열(n에 대한 4바이트 uint32_t와 그 뒤에 n바이트가 뒤따름) |
| 0x7b | UTF-8 문자열(n에 대한 8바이트 uint64_t와 그 뒤에 n바이트가 뒤따름) |
| 0x7f | UTF-8 문자열, UTF-8 문자열들이 뒤따르며 "break"로 종료됨 |
| 0x80..0x97 | 배열(0x00..0x17개의 데이터 항목이 뒤따름) |
| 0x98 | 배열(n에 대한 1바이트 uint8_t와 그 뒤에 n개의 데이터 항목이 뒤따름) |
| 0x99 | 배열(n에 대한 2바이트 uint16_t와 그 뒤에 n개의 데이터 항목이 뒤따름) |
| 0x9a | 배열(n에 대한 4바이트 uint32_t와 그 뒤에 n개의 데이터 항목이 뒤따름) |
| 0x9b | 배열(n에 대한 8바이트 uint64_t와 그 뒤에 n개의 데이터 항목이 뒤따름) |
| 0x9f | 배열, 데이터 항목들이 뒤따르며 "break"로 종료됨 |
| 0xa0..0xb7 | 맵(0x00..0x17쌍의 데이터 항목이 뒤따름) |
| 0xb8 | 맵(n에 대한 1바이트 uint8_t와 그 뒤에 n쌍의 데이터 항목이 뒤따름) |
| 0xb9 | 맵(n에 대한 2바이트 uint16_t와 그 뒤에 n쌍의 데이터 항목이 뒤따름) |
| 0xba | 맵(n에 대한 4바이트 uint32_t와 그 뒤에 n쌍의 데이터 항목이 뒤따름) |
| 0xbb | 맵(n에 대한 8바이트 uint64_t와 그 뒤에 n쌍의 데이터 항목이 뒤따름) |
| 0xbf | 맵, 데이터 항목의 쌍들이 뒤따르며 "break"로 종료됨 |
| 0xc0 | 텍스트 기반 날짜/시간(데이터 항목이 뒤따름; 섹션 3.4.1 참조) |
| 0xc1 | 에포크 기반 날짜/시간(데이터 항목이 뒤따름; 섹션 3.4.2 참조) |
| 0xc2 | 부호 없는 큰 수(데이터 항목 "바이트 문자열"이 뒤따름) |
| 0xc3 | 음의 큰 수(데이터 항목 "바이트 문자열"이 뒤따름) |
| 0xc4 | 십진 분수(데이터 항목 "배열"이 뒤따름; 섹션 3.4.4 참조) |
| 0xc5 | 큰 부동소수점 수(데이터 항목 "배열"이 뒤따름; 섹션 3.4.4 참조) |
| 0xc6..0xd4 | (태그) |
| 0xd5..0xd7 | 예상 변환(데이터 항목이 뒤따름; 섹션 3.4.5.2 참조) |
| 0xd8..0xdb | (추가 태그; 태그 번호의 1/2/4/8바이트와 그 뒤에 데이터 항목이 뒤따름) |
| 0xe0..0xf3 | (단순 값) |
| 0xf4 | false |
| 0xf5 | true |
| 0xf6 | null |
| 0xf7 | undefined |
| 0xf8 | (단순 값, 1바이트가 뒤따름) |
| 0xf9 | 반정밀도 부동소수점(2바이트 IEEE 754) |
| 0xfa | 단정밀도 부동소수점(4바이트 IEEE 754) |
| 0xfb | 배정밀도 부동소수점(8바이트 IEEE 754) |
| 0xff | "break" 정지 코드 |
CBOR 항목의 올바른 형식 여부는 그림 1의 의사 코드로 검사할 수 있다. 데이터는 다음 경우에 그리고 그 경우에만 올바른 형식이다.¶
의사 코드는 다음 전제 조건을 가진다.¶
well_formed는 올바른 형식의
정길이 항목에 대해 주요 타입을 반환하지만, 부정 길이 항목에 대해서는 99를 반환한다
(또는 breakable이 설정된 경우에만 "break" 정지 코드에 대해 -1).
이는 well_formed_indefinite에서 부정 길이 문자열이
청크로 정길이 문자열만 포함하는지 확인하는 데 사용된다.¶
well_formed(breakable = false) {
// process initial bytes
ib = uint(take(1));
mt = ib >> 5;
val = ai = ib & 0x1f;
switch (ai) {
case 24: val = uint(take(1)); break;
case 25: val = uint(take(2)); break;
case 26: val = uint(take(4)); break;
case 27: val = uint(take(8)); break;
case 28: case 29: case 30: fail();
case 31:
return well_formed_indefinite(mt, breakable);
}
// process content
switch (mt) {
// case 0, 1, 7 do not have content; just use val
case 2: case 3: take(val); break; // bytes/UTF-8
case 4: for (i = 0; i < val; i++) well_formed(); break;
case 5: for (i = 0; i < val*2; i++) well_formed(); break;
case 6: well_formed(); break; // 1 embedded data item
case 7: if (ai == 24 && val < 32) fail(); // bad simple
}
return mt; // definite-length data item
}
well_formed_indefinite(mt, breakable) {
switch (mt) {
case 2: case 3:
while ((it = well_formed(true)) != -1)
if (it != mt) // need definite-length chunk
fail(); // of same type
break;
case 4: while (well_formed(true) != -1); break;
case 5: while (well_formed(true) != -1) well_formed(); break;
case 7:
if (breakable)
return -1; // signal break out
else fail(); // no enclosing indefinite
default: fail(); // wrong mt
}
return 99; // indefinite-length data item
}
완전한 CBOR 디코더에 남는 복잡성은 디코딩된 데이터를 적절한 형태로 애플리케이션에 제시하는 것에 관한 것임에 유의한다.¶
주요 타입 0과 1은 양수/음수에 대한 if-then-else를 실제로 수행하지 않고도 부호 있는 정수에서 C로 인코딩될 수 있도록 설계되어 있다(그림 2). 이는 주요 타입 1에 대한 변환인 (-1-n)이 C 부호 없는 산술에서 ~n(비트 단위 보수)과 같다는 사실을 사용한다. 그런 다음 음수의 경우 ~n은 (-1)^n으로 표현할 수 있고, 0^n은 음이 아닌 경우 n을 변경하지 않고 둔다. 숫자의 부호는 숫자의 비트 길이보다 하나 적게 산술 시프트하여 음수에 대해 -1, 음이 아닌 값(0 또는 양수)에 대해 0으로 변환할 수 있다(예: 64비트 숫자의 경우 63만큼).¶
void encode_sint(int64_t n) {
uint64t ui = n >> 63; // extend sign to whole length
unsigned mt = ui & 0x20; // extract (shifted) major type
ui ^= n; // complement negatives
if (ui < 24)
*p++ = mt + ui;
else if (ui < 256) {
*p++ = mt + 24;
*p++ = ui;
} else
...
반정밀도 부동소수점 수는 2008년에야 IEEE 754에 추가되었으므로 [IEEE754], 오늘날의 프로그래밍 플랫폼은 여전히 이에 대한 지원이 제한적인 경우가 많다. 그러한 지원이 없어도 적어도 디코딩 지원을 포함하는 것은 매우 쉽다. C 언어로 된 반정밀도 부동소수점 수용 작은 디코더의 예는 그림 3에 나와 있다. Python용 유사한 프로그램은 그림 4에 있으며, 이 코드는 2바이트 값이 이미 네트워크 바이트 순서의 (부호 없는 short) 정수로 디코딩되었다고 가정한다(부록 C의 의사 코드에서 수행되는 것처럼).¶
#include <math.h>
double decode_half(unsigned char *halfp) {
unsigned half = (halfp[0] << 8) + halfp[1];
unsigned exp = (half >> 10) & 0x1f;
unsigned mant = half & 0x3ff;
double val;
if (exp == 0) val = ldexp(mant, -24);
else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
else val = mant == 0 ? INFINITY : NAN;
return half & 0x8000 ? -val : val;
}
import struct
from math import ldexp
def decode_single(single):
return struct.unpack("!f", struct.pack("!I", single))[0]
def decode_half(half):
valu = (half & 0x7fff) << 13 | (half & 0x8000) << 16
if ((half & 0x7c00) != 0x7c00):
return ldexp(decode_single(valu), 112)
return decode_single(valu | 0x7f800000)
CBOR 제안은 컴퓨터 자체의 역사만큼이나 긴 이진 형식의 역사를 따른다. 서로 다른 형식은 서로 다른 목표를 가져 왔다. 대부분의 경우, 형식의 목표는 명시된 적이 없지만, 그 형식이 처음 사용된 맥락에서 때때로 암시될 수 있다. 일부 형식은 보편적으로 사용할 수 있도록 의도되었지만, 역사는 어떤 이진 형식도 모든 프로토콜과 애플리케이션의 요구를 충족하지 못한다는 것을 증명했다.¶
CBOR는 일련의 목표에서 출발하여 바로 그 목표들만 충족하려고 시도한다는 점에서 이러한 여러 형식과 다르다. 이 섹션은 독자가 특정 프로토콜이나 애플리케이션에 CBOR를 사용할지 다른 형식을 사용할지 결정하는 데 도움을 주기 위해, 수십 가지 형식 중 일부를 CBOR의 목표와 비교한다.¶
여기서의 논의는 어떤 형식에 대한 비판을 의도한 것이 아님에 유의한다. 우리가 아는 한, CBOR 이전의 어떤 형식도 우리가 부여한 우선순위로 CBOR의 목표를 포괄하도록 의도되지 않았다. 섹션 1.1의 목표를 간단히 요약하면 다음과 같다.¶
다른 설계 목표 집합과 관련한 CBOR 및 다른 형식에 대한 논의는 [RFC8618]의 섹션 5 및 부록 C에 제공되어 있다.¶
[ASN.1]은 많은 직렬화를 가진다. IETF에서는 DER 및 BER이 가장 일반적이다. 직렬화된 출력은 많은 항목에 대해 특별히 간결하지 않으며, 숫자 항목을 디코딩하는 데 필요한 코드는 제약 장치에서 복잡할 수 있다.¶
IETF 프로토콜 중 Packed Encoding Rules(PER)의 여러 변형 중 하나를 채택한 것은 거의 없다(있더라도). 여기에는 여러 이유가 있을 수 있지만, 흔히 언급되는 이유 중 하나는 PER이 데이터 항목의 표면 구조를 구문 분석하는 데에도 스키마를 사용하여 상당한 도구 지원을 요구한다는 것이다. 사용 중인 ASN.1 스키마 언어에는 서로 다른 버전도 있어, 이는 채택을 저해하기도 했다.¶
[MessagePack]은 CBOR와 여러 속성에서 유사한, 간결하고 널리 구현된 카운트 기반 이진 직렬화 형식이지만, 다소 덜 규칙적이다. 데이터 모델은 JSON 데이터를 표현하는 데 사용할 수 있지만, MessagePack은 많은 원격 프로시저 호출(RPC) 애플리케이션과 데이터의 장기 저장에도 사용되어 왔다.¶
MessagePack은 2011년경 처음 공개된 이후 본질적으로 안정적이었으며, 아직 전환을 겪지 않았다. MessagePack의 발전은 기존 저장 데이터와의 완전한 하위 호환성을 유지해야 한다는 명령에 의해 저해되며, 확장에 사용할 수 있는 바이트코드는 거의 남아 있지 않다. 인코딩에서 이진 문자열과 텍스트 문자열을 분리하라는 MessagePack 사용자 커뮤니티의 수년간 반복된 요청은 최근 MessagePack의 "raw" 데이터를 이진 데이터와 텍스트 데이터에 대한 용도 사이에서 모호하게 남겨 두는 확장 제안으로 이어졌다. MessagePack의 확장 메커니즘은 여전히 불명확하다.¶
[BSON]은 MongoDB 데이터베이스에서 JSON 유사 맵(JSON 객체)을 저장하기 위해 개발된 데이터 형식이다. 주요한 구별 특징은 제자리 업데이트 기능이며, 이는 간결한 표현을 방해한다. BSON은 맵 키를 제외하고는 카운트 기반 표현을 사용하며, 맵 키는 널 바이트로 종료된다. BSON은 전송선상에서 JSON 유사 객체를 표현하는 데 사용할 수 있지만, 그 명세는 데이터베이스 애플리케이션의 요구 사항이 지배하며 다소 바로크식이 되었다. BSON 확장이 어떻게 구현될지의 상태는 여전히 불명확하다.¶
Message Services Data Transmission(MSDTP)은 간결한 메시지 형식의 매우 이른 예이며, 1976년에 작성된 [RFC0713]에 설명되어 있다. 이는 역사적 가치 때문에 여기에 포함되었으며, 널리 사용된 적이 있어서가 아니다.¶
인코더와 디코더의 코드 간결성이라는 CBOR의 설계 목표가 전송선상의 간결성이라는 목표보다 더 높은 우선순위이지만, 많은 사람은 전송 크기에 주목한다. 표 8은 단순한 중첩 배열 [1, [2, 3]]에 대한 몇 가지 인코딩 예를 보여 준다. 인코딩에서 어떤 형태의 부정 길이 인코딩을 지원하는 경우, [_ 1, [2, 3]](외부 배열의 부정 길이)도 표시되어 있다.¶
| 형식 | [1, [2, 3]] | [_ 1, [2, 3]] |
|---|---|---|
| RFC 713 | c2 05 81 c2 02 82 83 | |
| ASN.1 BER | 30 0b 02 01 01 30 06 02 01 02 02 01 03 | 30 80 02 01 01 30 06 02 01 02 02 01 03 00 00 |
| MessagePack | 92 01 92 02 03 | |
| BSON | 22 00 00 00 10 30 00 01 00 00 00 04 31 00 13 00 00 00 10 30 00 02 00 00 00 10 31 00 03 00 00 00 00 00 | |
| CBOR | 82 01 82 02 03 | 9f 01 82 02 03 ff |
CBOR 데이터 항목을 디코딩할 때 발생할 수 있는 올바른 형식 오류의 기본 종류는 세 가지이다.¶
부록 C에서 첫 번째 종류의 오류는 첫 번째 단락과 글머리표 목록("남은 바이트가 없음"을 요구함)에서 다루어지고, 두 번째 종류의 오류는 두 번째 단락/글머리표 목록 ("n바이트를 더 이상 사용할 수 없으면" 실패함)에서 다루어진다. 세 번째 종류의 오류는 의사 코드에서 다음 순서의 특정 fail() 호출 인스턴스로 식별된다.¶
이 하위 섹션은 올바른 형식이 아닌 CBOR 데이터 항목에 대한 몇 가지 예를 보여 준다. 각 예는 바이트 시퀀스이며, 각 바이트는 16진수로 표시된다. 목록의 여러 예는 쉼표로 구분된다.¶
올바른 형식 오류 종류 1(데이터가 너무 많음)의 예는 올바른 형식으로 인코딩된 CBOR 데이터 항목에 데이터를 추가하여 쉽게 만들 수 있다.¶
마찬가지로, 올바른 형식 오류 종류 2(데이터가 너무 적음)의 예는 올바른 형식으로 인코딩된 CBOR 데이터 항목을 잘라서 만들 수 있다. 테스트 모음에서는 완료되기 위해 많은 양의 추가가 필요한 불완전한 데이터 항목으로 구체적으로 테스트하는 것이 유익할 수 있다 (예를 들어 매우 큰 크기의 문자열 인코딩을 시작하는 방식).¶
입력의 조기 종료는 헤드에서 또는 포함된 데이터 안에서 발생할 수 있다. 그 데이터는 단순 문자열이거나, 카운트되거나 "break" 정지 코드로 끝났어야 하는 포함 데이터 항목일 수 있다.¶
올바른 형식 오류 종류 3(구문 오류)의 다섯 하위 종류에 대한 몇 가지 예는 아래에 표시되어 있다.¶
소개에서 논의한 것처럼, 이 문서는 RFC 7049의 교환 형식과 완전한 호환성을 유지하면서 RFC 7049를 공식적으로 폐기한다. 이 문서는 편집상 개선, 추가 세부 사항 및 정오표 수정을 제공한다. 이 문서는 형식의 새 버전을 만들지 않는다.¶
RFC 7049의 검증된 두 정오표, [Err3764] 및 [Err3770]는 본문에 있는 두 인코딩 예와 관련되어 있었고, 이는 수정되었다 (섹션 3.4.3: "29" -> "49", 섹션 5.5: "0b000_11101" -> "0b000_11001"). 또한 RFC 7049에는 단순 값에 대해 수치 값 24를 사용하는 예 [Err5917]가 포함되어 있었는데, 이는 올바른 형식이 아니므로 이 예는 제거되었다. 정오표 보고서 5763 [Err5763]은 태그 정의 문구의 오류를 지적했으며, 이는 섹션 3.4를 다시 작성하는 과정에서 해결되었다. 정오표 보고서 5434 [Err5434]는 부록 E의 Universal Binary JSON (UBJSON) 예가 정오표 보고서 제출 당시의 최신 UBJSON 버전을 더 이상 준수하지 않는다고 지적했다. 2013년 이후 UBJSON 명세가 완전히 변경된 것으로 밝혀졌으므로 이 예는 제거되었다. 다른 정오표 보고서 [Err4409] [Err4963] [Err4964]는 정규 인코딩의 맵 키 정렬 규칙이 부담스럽다고 불평했으며, 이는 정규 인코딩 제안을 재검토하고 결정적 인코딩 제안 (아래 설명)으로 대체하는 결과를 낳았다. 정오표 보고서 4294의 편집상 제안 [Err4294]도 구현되었다(섹션 3.2.2의 마지막 예에 있는 주석에 "Second value"를 추가하여 대칭성을 개선).¶
그 밖의 사무적 변경 사항에는 다음이 포함된다.¶
IANA 고려 사항은 일반적으로 갱신되었다(예: 이제 명세의 저자로 CBOR Working Group을 가리키는 등의 사무적 변경). 각각의 IANA 레지스트리에 대한 참조가 정보 참고 문헌에 추가되었다.¶
"Concise Binary Object Representation (CBOR) Tags" 레지스트리 [IANA.cbor-tags]에서, 256부터 32767까지의 공간("1+2"의 하위 절반)에 있는 태그는 더 이상 First Come First Served로 할당되지 않는다. 이 범위는 이제 Specification Required이다.¶
문서를 개정하면서, 정오표 보고서 처리 외에도, 작업 그룹은 다양한 애플리케이션 집합에서 CBOR를 사용한 거의 7년간의 경험을 활용했다. 이는 설명을 위한 표 추가를 포함한 여러 편집상 변경으로 이어졌지만, 또한 일부 측면을 강조하고 다른 측면을 덜 강조하는 결과도 낳았다.¶
중요한 추가 사항은 CBOR 데이터 모델과 CBOR 처리에 관여하는 그 작은 변형들을 논의하는 섹션 2이다. 이러한 변형(기본 일반, 확장 일반, 특정)에 대한 용어 도입은 문서의 다른 곳에서 더 간결한 언어를 가능하게 하고, 구현에 대한 기대와 형식의 확장성 기능을 명확히 하는 데도 도움이 된다.¶
JSON 생태계에서 파생된 형식으로서, RFC 7049는 당시 JavaScript에서 물려받은 JSON 숫자 시스템의 영향을 받았다. JSON은 정수와 부동소수점 값을 구별하여 제공하지 않는다 (그리고 후자는 형식에서 십진수이다). CBOR는 숫자의 이진 표현을 제공하며, 이는 정수와 부동소수점 값 사이에서 서로 다르다. 구현 및 사용 경험은 이 두 숫자 영역 사이의 분리를 문서에서 더 명확히 해야 함을 시사했다. 정수가 부동소수점 값을 매끄럽게 대신할 수 있음을 암시하는 문구는 제거되었다. 또한 JSON을 CBOR로 변환할 때 이러한 타입을 처리하기 위한 제안 (I-JSON [RFC7493] 기반)이 추가되었고, 특정 반올림 메커니즘의 사용이 권장되었다.¶
데이터 모델의 단일 값에 대해, CBOR는 종종 여러 인코딩 선택지를 제공한다. 새 섹션(섹션 4)은 "선호 직렬화"(섹션 4.1)라는 용어를 도입하고 다양한 종류의 데이터 항목에 대해 이를 정의한다. 이 용어를 바탕으로, 그 섹션은 CBOR 기반 프로토콜이 RFC 7049의 "canonical" 및 "canonicalization"이라는 용어를 피하면서 "결정적 인코딩"(섹션 4.2)을 정의할 수 있는 방법을 논의한다. "Core Deterministic Encoding Requirements"(섹션 4.2.1)의 제안은 그러한 프로토콜 정의 인코딩 요구 사항에 대한 일반 지원을 가능하게 한다. 이 문서는 RFC 7049에서 제안한 맵 정렬을 인코딩된 키의 단순한 사전식 정렬로 단순화하여 결정적 인코딩 구현을 더욱 쉽게 한다. 이전 제안의 설명은 이제 "길이 우선 맵 키 정렬"(섹션 4.2.3)이라고 불리는 대안으로 유지된다.¶
올바른 형식 및 유효한 데이터에 대한 용어가 다듬어지고 더 엄격하게 사용되었으며, 예 밖에서는 "syntax error", "decoding error", "strict mode"와 같은 덜 잘 정의된 대체 용어를 피했다. 또한 CBOR 수준의 유효성을 넘어 애플리케이션이 입력 데이터에 대해 갖는 세 번째 요구 수준이 이제 명시적으로 언급된다. 올바른 형식(전혀 처리 가능), 유효함 (유효성 검사 일반 디코더가 검사), 예상 입력 (애플리케이션이 검사)은 수용 가능성 계층의 위계로 다루어진다.¶
올바른 형식이 아닌 단순 값의 처리는 본문과 의사 코드에서 명확해졌다. 부록 F가 추가되어 올바른 형식 오류를 논의하고 그 예를 제공한다. 의사 코드는 더 이식 가능하도록 갱신되었으며, 몇 가지 이식성 고려 사항도 추가되었다.¶
유효성에 대한 논의는 두 영역에서 더 명확해졌다. 맵 유효성(중복 키 처리)이 명확해졌고, 특정 구현 선택의 적용 범위가 설명되었다. 또한 태그, 태그 번호 및 태그 내용에 대한 용어를 간소화하면서, 태그 유효성에 대한 논의가 추가되었고, 태그 내용에 대한 제한이 일반적으로 그리고 태그 1에 대해 구체적으로 명확해졌다.¶
직렬화 순서에 의존하는 의미를 가진 태그를 정의하는 것에 대한 구현 참고(및 향후 태그 정의를 위한 참고)가 섹션 3.4에 추가되었다.¶
태그 35는 이 문서에서 정의되지 않는다. RFC 7049의 정의에 기반한 등록은 그대로 유지된다.¶
"인수"와 "헤드"에 대한 용어가 섹션 3에 도입되어, 이후 논의를 단순화했다.¶
보안 고려 사항(섹션 10)은 대부분 다시 작성되고 크게 확장되었다. 문서의 여러 다른 곳에서도 디코더가 올바른 형식 오류를 단순히 용인할 수 없음을 이제 더 명시적으로 밝힌다.¶
CBOR는 MessagePack에서 영감을 받았다. MessagePack은 Sadayuki Furuhashi("frsyuki")가 개발하고 홍보했다. MessagePack에 대한 이 참조는 오직 출처 표시를 위한 것이다. CBOR는 서로 다른 설계 목표와 요구 사항을 가지므로 MessagePack의 버전이나 대체물을 의도하지 않는다.¶
원래 MessagePack 명세를 넘어서는 기능의 필요성은 2012년경 거의 같은 시기에 많은 사람들에게 분명해졌다. BinaryPack은 MessagePack의 작은 파생물로, binaryjs 프로젝트를 위해 Eric Zhang이 개발했다. 유사하지만 다른 확장은 Tim Caswell이 자신의 msgpack-js 및 msgpack-js-browser 프로젝트를 위해 만들었다. 많은 사람이 MessagePack을 확장하여 텍스트 문자열 표현을 바이트 문자열 표현과 분리하는 논의에 기여했다.¶
CBOR에서 추가 정보의 인코딩은 CoAP를 위해 Klaus Hartke가 설계한 길이 정보 인코딩에서 영감을 받았다.¶
이 문서는 또한 많은 사람들이 제안한 내용을 포함하고 있으며, 특히 Dan Frost, James Manger, Jeffrey Yasskin, Joe Hildebrand, Keith Moore, Laurence Lundblade, Matthew Lepinski, Michael Richardson, Nico Williams, Peter Occil, Phillip Hallam-Baker, Ray Polk, Stuart Cheshire, Tim Bray, Tony Finch, Tony Hansen, 및 Yaron Sheffer의 제안을 포함한다. Benjamin Kaduk은 IESG 처리 중 광범위한 검토를 제공했다. Éric Vyncke, Erik Kline, Robert Wilton, 및 Roman Danyliw는 추가 IESG 의견을 제공했으며, 여기에는 Eve Schooler의 IoT directorate 검토도 포함되었다.¶