@@ -2,8 +2,12 @@ package certificate
22
33import (
44 "bytes"
5+ "crypto/x509"
6+ "crypto/x509/pkix"
7+ "encoding/asn1"
58 "encoding/json"
69 "flag"
10+ "strings"
711 "testing"
812
913 "github.com/smallstep/assert"
@@ -138,3 +142,148 @@ func TestInspectCertificateRequest(t *testing.T) {
138142 }
139143
140144}
145+
146+ func TestInspectCertificates_Logotypes (t * testing.T ) {
147+ mustMarshal := func (val interface {}) []byte {
148+ b , err := asn1 .Marshal (val )
149+ if err != nil {
150+ t .Fatal (err )
151+ }
152+ return b
153+ }
154+
155+ wrapExplicit := func (tag int , payload []byte ) []byte {
156+ var lenBytes []byte
157+ length := len (payload )
158+ if length < 128 {
159+ lenBytes = []byte {byte (length )}
160+ } else if length < 256 {
161+ lenBytes = []byte {0x81 , byte (length )}
162+ } else {
163+ lenBytes = []byte {0x82 , byte (length >> 8 ), byte (length & 0xff )}
164+ }
165+ result := []byte {byte (0xa0 | tag )}
166+ result = append (result , lenBytes ... )
167+ result = append (result , payload ... )
168+ return result
169+ }
170+
171+ wrapSequence := func (payload []byte ) []byte {
172+ var lenBytes []byte
173+ length := len (payload )
174+ if length < 128 {
175+ lenBytes = []byte {byte (length )}
176+ } else if length < 256 {
177+ lenBytes = []byte {0x81 , byte (length )}
178+ } else {
179+ lenBytes = []byte {0x82 , byte (length >> 8 ), byte (length & 0xff )}
180+ }
181+ result := []byte {0x30 }
182+ result = append (result , lenBytes ... )
183+ result = append (result , payload ... )
184+ return result
185+ }
186+
187+ // Direct CHOICE value [0] LogotypeData
188+ directDataBytes := mustMarshal (LogotypeData {
189+ Image : []LogotypeImage {
190+ {
191+ ImageDetails : LogotypeDetails {
192+ MediaType : "image/png" ,
193+ LogotypeURI : []string {"https://example.com/subject-direct.png" },
194+ },
195+ },
196+ },
197+ })
198+ directDataBytes [0 ] = 0xa0 // choice tag [0] implicit
199+
200+ // Indirect CHOICE value [1] LogotypeReference
201+ indirectRefBytes := mustMarshal (LogotypeReference {
202+ RefStructURI : []string {"https://example.com/issuer-indirect.png" },
203+ })
204+ indirectRefBytes [0 ] = 0xa1 // choice tag [1] implicit
205+
206+ // Community LOGOS list element (direct Choice [0] LogotypeData)
207+ communityDirectBytes := mustMarshal (LogotypeData {
208+ Image : []LogotypeImage {
209+ {
210+ ImageDetails : LogotypeDetails {
211+ MediaType : "image/svg+xml" ,
212+ LogotypeURI : []string {"https://example.com/community-direct.svg" },
213+ },
214+ },
215+ },
216+ })
217+ communityDirectBytes [0 ] = 0xa0
218+
219+ // Community LOGOS list element (indirect Choice [1] LogotypeReference)
220+ communityIndirectBytes := mustMarshal (LogotypeReference {
221+ RefStructURI : []string {"https://example.com/community-indirect.png" },
222+ })
223+ communityIndirectBytes [0 ] = 0xa1
224+
225+ // OtherLogotypeInfo element
226+ otherInfoBytes := mustMarshal (OtherLogotypeInfo {
227+ LogotypeType : asn1.ObjectIdentifier {1 , 3 , 6 , 1 , 5 , 5 , 7 , 1 , 12 , 99 },
228+ Info : asn1.RawValue {
229+ FullBytes : communityDirectBytes ,
230+ },
231+ })
232+
233+ // Wrap in communityLogos explicit tag [0]
234+ communitySeqBytes := append (communityDirectBytes , communityIndirectBytes ... )
235+ communityLogosDER := wrapExplicit (0 , wrapSequence (communitySeqBytes ))
236+
237+ // Wrap in issuerLogo explicit tag [1]
238+ issuerLogoDER := wrapExplicit (1 , indirectRefBytes )
239+
240+ // Wrap in subjectLogo explicit tag [2]
241+ subjectLogoDER := wrapExplicit (2 , directDataBytes )
242+
243+ // Wrap in otherLogos explicit tag [3]
244+ otherLogosDER := wrapExplicit (3 , wrapSequence (otherInfoBytes ))
245+
246+ var extnBytes []byte
247+ extnBytes = append (extnBytes , communityLogosDER ... )
248+ extnBytes = append (extnBytes , issuerLogoDER ... )
249+ extnBytes = append (extnBytes , subjectLogoDER ... )
250+ extnBytes = append (extnBytes , otherLogosDER ... )
251+
252+ extDER := wrapSequence (extnBytes )
253+
254+ certs , err := pemutil .ParseCertificateBundle (pemData )
255+ if err != nil {
256+ t .Fatal (err )
257+ }
258+ crt := certs [0 ]
259+ crt .Extensions = append (crt .Extensions , pkix.Extension {
260+ Id : asn1.ObjectIdentifier {1 , 3 , 6 , 1 , 5 , 5 , 7 , 1 , 12 },
261+ Value : extDER ,
262+ })
263+
264+ app := & cli.App {}
265+ set := flag .NewFlagSet ("contrive" , 0 )
266+ _ = set .String ("format" , "text" , "" )
267+ ctx := cli .NewContext (app , set , nil )
268+
269+ var buf bytes.Buffer
270+ err = inspectCertificates (ctx , []* x509.Certificate {crt }, & buf )
271+ assert .NoError (t , err )
272+
273+ output := buf .String ()
274+ t .Logf ("Output:\n %s" , output )
275+
276+ if ! strings .Contains (output , "Logotype URI: https://example.com/community-direct.svg" ) {
277+ t .Error ("missing community-direct URI" )
278+ }
279+ if ! strings .Contains (output , "Logotype URI: https://example.com/community-indirect.png" ) {
280+ t .Error ("missing community-indirect URI" )
281+ }
282+ if ! strings .Contains (output , "Logotype URI: https://example.com/issuer-indirect.png" ) {
283+ t .Error ("missing issuer-indirect URI" )
284+ }
285+ if ! strings .Contains (output , "Logotype URI: https://example.com/subject-direct.png" ) {
286+ t .Error ("missing subject-direct URI" )
287+ }
288+ }
289+
0 commit comments