@@ -3,13 +3,19 @@ import { encodeLength } from '../../src/asn1/length';
33import { parseAlgorithmAndKey , readTLV } from '../../src/asn1/parse' ;
44import {
55 encodeBitString ,
6+ encodeInteger ,
67 encodeNull ,
78 encodeObjectIdentifier ,
89 encodeOctetString ,
910 encodeSequence ,
1011} from '../../src/asn1/primitives' ;
1112import { InvalidEncodingError } from '../../src/errors' ;
1213
14+ function encodeContextSpecific ( tag : number , value : Uint8Array ) : Uint8Array {
15+ const length = encodeLength ( value . length ) ;
16+ return Uint8Array . from ( [ tag , ...length , ...value ] ) ;
17+ }
18+
1319describe ( 'asn1 parse' , ( ) => {
1420 it ( 'reads TLV with short-form length' , ( ) => {
1521 const tlv = new Uint8Array ( [ 0x04 , 0x03 , 0x01 , 0x02 , 0x03 ] ) ;
@@ -48,15 +54,96 @@ describe('asn1 parse', () => {
4854 expect ( Array . from ( parsed . keyBytes ) ) . toEqual ( [ 0xde , 0xad , 0xbe , 0xef ] ) ;
4955 } ) ;
5056
51- it ( 'extracts OID + key bytes from OCTET STRING' , ( ) => {
57+ it ( 'extracts OID + key bytes from OCTET STRING (PKCS8) ' , ( ) => {
5258 const oid = '1.3.6.1.4.1.2.267.7.6.5' ;
59+ const version = encodeInteger ( 0 ) ;
5360 const algorithm = encodeSequence ( [ encodeObjectIdentifier ( oid ) , encodeNull ( ) ] ) ;
5461 const keyBytes = new Uint8Array ( [ 0x00 , 0x11 , 0x22 , 0x33 ] ) ;
5562 const key = encodeOctetString ( keyBytes ) ;
56- const pkcs8 = encodeSequence ( [ algorithm , key ] ) ;
63+ const pkcs8 = encodeSequence ( [ version , algorithm , key ] ) ;
5764
5865 const parsed = parseAlgorithmAndKey ( pkcs8 ) ;
5966 expect ( parsed . oid ) . toBe ( oid ) ;
6067 expect ( Array . from ( parsed . keyBytes ) ) . toEqual ( [ 0x00 , 0x11 , 0x22 , 0x33 ] ) ;
6168 } ) ;
69+
70+ it ( 'accepts OneAsymmetricKey with publicKey when version is 1' , ( ) => {
71+ const oid = '1.3.6.1.4.1.2.267.7.6.5' ;
72+ const version = encodeInteger ( 1 ) ;
73+ const algorithm = encodeSequence ( [ encodeObjectIdentifier ( oid ) , encodeNull ( ) ] ) ;
74+ const keyBytes = new Uint8Array ( [ 0xaa , 0xbb , 0xcc , 0xdd ] ) ;
75+ const privateKey = encodeOctetString ( keyBytes ) ;
76+ const publicKey = encodeBitString ( new Uint8Array ( [ 0x01 , 0x02 , 0x03 ] ) ) ;
77+ const publicKeyField = encodeContextSpecific ( 0xa1 , publicKey ) ;
78+ const pkcs8 = encodeSequence ( [ version , algorithm , privateKey , publicKeyField ] ) ;
79+
80+ const parsed = parseAlgorithmAndKey ( pkcs8 ) ;
81+ expect ( parsed . oid ) . toBe ( oid ) ;
82+ expect ( Array . from ( parsed . keyBytes ) ) . toEqual ( [ 0xaa , 0xbb , 0xcc , 0xdd ] ) ;
83+ } ) ;
84+
85+ it ( 'rejects publicKey field when version is 0' , ( ) => {
86+ const oid = '1.3.6.1.4.1.2.267.7.6.5' ;
87+ const version = encodeInteger ( 0 ) ;
88+ const algorithm = encodeSequence ( [ encodeObjectIdentifier ( oid ) , encodeNull ( ) ] ) ;
89+ const keyBytes = new Uint8Array ( [ 0x10 , 0x20 , 0x30 , 0x40 ] ) ;
90+ const privateKey = encodeOctetString ( keyBytes ) ;
91+ const publicKey = encodeBitString ( new Uint8Array ( [ 0x09 , 0x08 , 0x07 ] ) ) ;
92+ const publicKeyField = encodeContextSpecific ( 0xa1 , publicKey ) ;
93+ const pkcs8 = encodeSequence ( [ version , algorithm , privateKey , publicKeyField ] ) ;
94+
95+ expect ( ( ) => parseAlgorithmAndKey ( pkcs8 ) ) . toThrow ( InvalidEncodingError ) ;
96+ } ) ;
97+
98+ it ( 'accepts AlgorithmIdentifier with absent parameters' , ( ) => {
99+ const oid = '1.3.6.1.4.1.2.267.7.4.4' ;
100+ const algorithm = encodeSequence ( [ encodeObjectIdentifier ( oid ) ] ) ; // No NULL
101+ const keyBytes = new Uint8Array ( [ 0x11 , 0x22 , 0x33 , 0x44 ] ) ;
102+ const key = encodeBitString ( keyBytes ) ;
103+ const spki = encodeSequence ( [ algorithm , key ] ) ;
104+
105+ const parsed = parseAlgorithmAndKey ( spki ) ;
106+ expect ( parsed . oid ) . toBe ( oid ) ;
107+ expect ( Array . from ( parsed . keyBytes ) ) . toEqual ( [ 0x11 , 0x22 , 0x33 , 0x44 ] ) ;
108+ } ) ;
109+
110+ it ( 'accepts AlgorithmIdentifier with explicit NULL parameters' , ( ) => {
111+ const oid = '1.3.6.1.4.1.2.267.7.4.4' ;
112+ const algorithm = encodeSequence ( [ encodeObjectIdentifier ( oid ) , encodeNull ( ) ] ) ;
113+ const keyBytes = new Uint8Array ( [ 0x55 , 0x66 , 0x77 , 0x88 ] ) ;
114+ const key = encodeBitString ( keyBytes ) ;
115+ const spki = encodeSequence ( [ algorithm , key ] ) ;
116+
117+ const parsed = parseAlgorithmAndKey ( spki ) ;
118+ expect ( parsed . oid ) . toBe ( oid ) ;
119+ expect ( Array . from ( parsed . keyBytes ) ) . toEqual ( [ 0x55 , 0x66 , 0x77 , 0x88 ] ) ;
120+ } ) ;
121+
122+ it ( 'rejects AlgorithmIdentifier with non-NULL parameters' , ( ) => {
123+ const oid = '1.3.6.1.4.1.2.267.7.4.4' ;
124+ // Use OCTET STRING as unsupported parameter type
125+ const badParams = encodeOctetString ( new Uint8Array ( [ 0x01 , 0x02 ] ) ) ;
126+ const algorithm = encodeSequence ( [ encodeObjectIdentifier ( oid ) , badParams ] ) ;
127+ const keyBytes = new Uint8Array ( [ 0xaa , 0xbb , 0xcc , 0xdd ] ) ;
128+ const key = encodeBitString ( keyBytes ) ;
129+ const spki = encodeSequence ( [ algorithm , key ] ) ;
130+
131+ expect ( ( ) => parseAlgorithmAndKey ( spki ) ) . toThrow ( InvalidEncodingError ) ;
132+ expect ( ( ) => parseAlgorithmAndKey ( spki ) ) . toThrow ( 'Unsupported AlgorithmIdentifier parameters' ) ;
133+ } ) ;
134+
135+ it ( 'rejects AlgorithmIdentifier with trailing data after NULL' , ( ) => {
136+ const oid = '1.3.6.1.4.1.2.267.7.4.4' ;
137+ // Manually construct AlgorithmIdentifier with NULL + extra bytes
138+ const oidEncoded = encodeObjectIdentifier ( oid ) ;
139+ const nullEncoded = encodeNull ( ) ;
140+ const extraBytes = new Uint8Array ( [ 0x00 , 0x00 ] ) ;
141+ const algorithmValue = new Uint8Array ( [ ...oidEncoded , ...nullEncoded , ...extraBytes ] ) ;
142+ const algorithm = encodeSequence ( [ algorithmValue ] ) ;
143+ const keyBytes = new Uint8Array ( [ 0x12 , 0x34 , 0x56 , 0x78 ] ) ;
144+ const key = encodeBitString ( keyBytes ) ;
145+ const spki = encodeSequence ( [ algorithm , key ] ) ;
146+
147+ expect ( ( ) => parseAlgorithmAndKey ( spki ) ) . toThrow ( InvalidEncodingError ) ;
148+ } ) ;
62149} ) ;
0 commit comments