1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
18 // A forkableWriter is an in-memory buffer that can be
19 // 'forked' to create new forkableWriters that bracket the
21 // pre, post := w.fork();
22 // the overall sequence of bytes represented is logically w+pre+post.
23 type forkableWriter
struct {
25 pre
, post
*forkableWriter
28 func newForkableWriter() *forkableWriter
{
29 return &forkableWriter
{new(bytes
.Buffer
), nil, nil}
32 func (f
*forkableWriter
) fork() (pre
, post
*forkableWriter
) {
33 if f
.pre
!= nil || f
.post
!= nil {
34 panic("have already forked")
36 f
.pre
= newForkableWriter()
37 f
.post
= newForkableWriter()
41 func (f
*forkableWriter
) Len() (l
int) {
52 func (f
*forkableWriter
) writeTo(out io
.Writer
) (n
int, err error
) {
53 n
, err
= out
.Write(f
.Bytes())
61 nn
, err
= f
.pre
.writeTo(out
)
69 nn
, err
= f
.post
.writeTo(out
)
75 func marshalBase128Int(out
*forkableWriter
, n
int64) (err error
) {
77 err
= out
.WriteByte(0)
82 for i
:= n
; i
> 0; i
>>= 7 {
86 for i
:= l
- 1; i
>= 0; i
-- {
87 o
:= byte(n
>> uint(i
*7))
92 err
= out
.WriteByte(o
)
101 func marshalInt64(out
*forkableWriter
, i
int64) (err error
) {
105 err
= out
.WriteByte(byte(i
>> uint((n
-1)*8)))
114 func int64Length(i
int64) (numBytes
int) {
130 func marshalBigInt(out
*forkableWriter
, n
*big
.Int
) (err error
) {
132 // A negative number has to be converted to two's-complement
133 // form. So we'll subtract 1 and invert. If the
134 // most-significant-bit isn't set then we'll need to pad the
135 // beginning with 0xff in order to keep the number negative.
136 nMinus1
:= new(big
.Int
).Neg(n
)
137 nMinus1
.Sub(nMinus1
, bigOne
)
138 bytes
:= nMinus1
.Bytes()
139 for i
:= range bytes
{
142 if len(bytes
) == 0 || bytes
[0]&0x80 == 0 {
143 err
= out
.WriteByte(0xff)
148 _
, err
= out
.Write(bytes
)
149 } else if n
.Sign() == 0 {
150 // Zero is written as a single 0 zero rather than no bytes.
151 err
= out
.WriteByte(0x00)
154 if len(bytes
) > 0 && bytes
[0]&0x80 != 0 {
155 // We'll have to pad this with 0x00 in order to stop it
156 // looking like a negative number.
157 err
= out
.WriteByte(0)
162 _
, err
= out
.Write(bytes
)
167 func marshalLength(out
*forkableWriter
, i
int) (err error
) {
171 err
= out
.WriteByte(byte(i
>> uint((n
-1)*8)))
180 func lengthLength(i
int) (numBytes
int) {
189 func marshalTagAndLength(out
*forkableWriter
, t tagAndLength
) (err error
) {
190 b
:= uint8(t
.class
) << 6
196 err
= out
.WriteByte(b
)
200 err
= marshalBase128Int(out
, int64(t
.tag
))
206 err
= out
.WriteByte(b
)
213 l
:= lengthLength(t
.length
)
214 err
= out
.WriteByte(0x80 |
byte(l
))
218 err
= marshalLength(out
, t
.length
)
223 err
= out
.WriteByte(byte(t
.length
))
232 func marshalBitString(out
*forkableWriter
, b BitString
) (err error
) {
233 paddingBits
:= byte((8 - b
.BitLength%8
) % 8)
234 err
= out
.WriteByte(paddingBits
)
238 _
, err
= out
.Write(b
.Bytes
)
242 func marshalObjectIdentifier(out
*forkableWriter
, oid
[]int) (err error
) {
243 if len(oid
) < 2 || oid
[0] > 2 ||
(oid
[0] < 2 && oid
[1] >= 40) {
244 return StructuralError
{"invalid object identifier"}
247 err
= marshalBase128Int(out
, int64(oid
[0]*40+oid
[1]))
251 for i
:= 2; i
< len(oid
); i
++ {
252 err
= marshalBase128Int(out
, int64(oid
[i
]))
261 func marshalPrintableString(out
*forkableWriter
, s
string) (err error
) {
263 for _
, c
:= range b
{
265 return StructuralError
{"PrintableString contains invalid character"}
269 _
, err
= out
.Write(b
)
273 func marshalIA5String(out
*forkableWriter
, s
string) (err error
) {
275 for _
, c
:= range b
{
277 return StructuralError
{"IA5String contains invalid character"}
281 _
, err
= out
.Write(b
)
285 func marshalUTF8String(out
*forkableWriter
, s
string) (err error
) {
286 _
, err
= out
.Write([]byte(s
))
290 func marshalTwoDigits(out
*forkableWriter
, v
int) (err error
) {
291 err
= out
.WriteByte(byte('0' + (v
/10)%10
))
295 return out
.WriteByte(byte('0' + v%10
))
298 func marshalFourDigits(out
*forkableWriter
, v
int) (err error
) {
300 for i
:= range bytes
{
301 bytes
[3-i
] = '0' + byte(v%10
)
304 _
, err
= out
.Write(bytes
[:])
308 func outsideUTCRange(t time
.Time
) bool {
310 return year
< 1950 || year
>= 2050
313 func marshalUTCTime(out
*forkableWriter
, t time
.Time
) (err error
) {
317 case 1950 <= year
&& year
< 2000:
318 err
= marshalTwoDigits(out
, int(year
-1900))
319 case 2000 <= year
&& year
< 2050:
320 err
= marshalTwoDigits(out
, int(year
-2000))
322 return StructuralError
{"cannot represent time as UTCTime"}
328 return marshalTimeCommon(out
, t
)
331 func marshalGeneralizedTime(out
*forkableWriter
, t time
.Time
) (err error
) {
333 if year
< 0 || year
> 9999 {
334 return StructuralError
{"cannot represent time as GeneralizedTime"}
336 if err
= marshalFourDigits(out
, year
); err
!= nil {
340 return marshalTimeCommon(out
, t
)
343 func marshalTimeCommon(out
*forkableWriter
, t time
.Time
) (err error
) {
344 _
, month
, day
:= t
.Date()
346 err
= marshalTwoDigits(out
, int(month
))
351 err
= marshalTwoDigits(out
, day
)
356 hour
, min
, sec
:= t
.Clock()
358 err
= marshalTwoDigits(out
, hour
)
363 err
= marshalTwoDigits(out
, min
)
368 err
= marshalTwoDigits(out
, sec
)
373 _
, offset
:= t
.Zone()
377 err
= out
.WriteByte('Z')
380 err
= out
.WriteByte('+')
382 err
= out
.WriteByte('-')
389 offsetMinutes
:= offset
/ 60
390 if offsetMinutes
< 0 {
391 offsetMinutes
= -offsetMinutes
394 err
= marshalTwoDigits(out
, offsetMinutes
/60)
399 err
= marshalTwoDigits(out
, offsetMinutes%60
)
403 func stripTagAndLength(in
[]byte) []byte {
404 _
, offset
, err
:= parseTagAndLength(in
, 0)
411 func marshalBody(out
*forkableWriter
, value reflect
.Value
, params fieldParameters
) (err error
) {
412 switch value
.Type() {
414 t
:= value
.Interface().(time
.Time
)
415 if outsideUTCRange(t
) {
416 return marshalGeneralizedTime(out
, t
)
418 return marshalUTCTime(out
, t
)
421 return marshalBitString(out
, value
.Interface().(BitString
))
422 case objectIdentifierType
:
423 return marshalObjectIdentifier(out
, value
.Interface().(ObjectIdentifier
))
425 return marshalBigInt(out
, value
.Interface().(*big
.Int
))
428 switch v
:= value
; v
.Kind() {
431 return out
.WriteByte(255)
433 return out
.WriteByte(0)
435 case reflect
.Int
, reflect
.Int8
, reflect
.Int16
, reflect
.Int32
, reflect
.Int64
:
436 return marshalInt64(out
, int64(v
.Int()))
442 // If the first element of the structure is a non-empty
443 // RawContents, then we don't bother serializing the rest.
444 if t
.NumField() > 0 && t
.Field(0).Type
== rawContentsType
{
447 bytes
:= make([]byte, s
.Len())
448 for i
:= 0; i
< s
.Len(); i
++ {
449 bytes
[i
] = uint8(s
.Index(i
).Uint())
451 /* The RawContents will contain the tag and
452 * length fields but we'll also be writing
453 * those ourselves, so we strip them out of
455 _
, err
= out
.Write(stripTagAndLength(bytes
))
462 for i
:= startingField
; i
< t
.NumField(); i
++ {
463 var pre
*forkableWriter
464 pre
, out
= out
.fork()
465 err
= marshalField(pre
, v
.Field(i
), parseFieldParameters(t
.Field(i
).Tag
.Get("asn1")))
472 sliceType
:= v
.Type()
473 if sliceType
.Elem().Kind() == reflect
.Uint8
{
474 bytes
:= make([]byte, v
.Len())
475 for i
:= 0; i
< v
.Len(); i
++ {
476 bytes
[i
] = uint8(v
.Index(i
).Uint())
478 _
, err
= out
.Write(bytes
)
482 var fp fieldParameters
483 for i
:= 0; i
< v
.Len(); i
++ {
484 var pre
*forkableWriter
485 pre
, out
= out
.fork()
486 err
= marshalField(pre
, v
.Index(i
), fp
)
493 switch params
.stringType
{
495 return marshalIA5String(out
, v
.String())
496 case tagPrintableString
:
497 return marshalPrintableString(out
, v
.String())
499 return marshalUTF8String(out
, v
.String())
503 return StructuralError
{"unknown Go type"}
506 func marshalField(out
*forkableWriter
, v reflect
.Value
, params fieldParameters
) (err error
) {
507 // If the field is an interface{} then recurse into it.
508 if v
.Kind() == reflect
.Interface
&& v
.Type().NumMethod() == 0 {
509 return marshalField(out
, v
.Elem(), params
)
512 if v
.Kind() == reflect
.Slice
&& v
.Len() == 0 && params
.omitEmpty
{
516 if params
.optional
&& reflect
.DeepEqual(v
.Interface(), reflect
.Zero(v
.Type()).Interface()) {
520 if v
.Type() == rawValueType
{
521 rv
:= v
.Interface().(RawValue
)
522 if len(rv
.FullBytes
) != 0 {
523 _
, err
= out
.Write(rv
.FullBytes
)
525 err
= marshalTagAndLength(out
, tagAndLength
{rv
.Class
, rv
.Tag
, len(rv
.Bytes
), rv
.IsCompound
})
529 _
, err
= out
.Write(rv
.Bytes
)
534 tag
, isCompound
, ok
:= getUniversalType(v
.Type())
536 err
= StructuralError
{fmt
.Sprintf("unknown Go type: %v", v
.Type())}
539 class
:= classUniversal
541 if params
.stringType
!= 0 && tag
!= tagPrintableString
{
542 return StructuralError
{"explicit string type given to non-string member"}
546 case tagPrintableString
:
547 if params
.stringType
== 0 {
548 // This is a string without an explicit string type. We'll use
549 // a PrintableString if the character set in the string is
550 // sufficiently limited, otherwise we'll use a UTF8String.
551 for _
, r
:= range v
.String() {
552 if r
>= utf8
.RuneSelf ||
!isPrintable(byte(r
)) {
553 if !utf8
.ValidString(v
.String()) {
554 return errors
.New("asn1: string not valid UTF-8")
561 tag
= params
.stringType
564 if outsideUTCRange(v
.Interface().(time
.Time
)) {
565 tag
= tagGeneralizedTime
570 if tag
!= tagSequence
{
571 return StructuralError
{"non sequence tagged as set"}
576 tags
, body
:= out
.fork()
578 err
= marshalBody(body
, v
, params
)
583 bodyLen
:= body
.Len()
585 var explicitTag
*forkableWriter
587 explicitTag
, tags
= tags
.fork()
590 if !params
.explicit
&& params
.tag
!= nil {
593 class
= classContextSpecific
596 err
= marshalTagAndLength(tags
, tagAndLength
{class
, tag
, bodyLen
, isCompound
})
602 err
= marshalTagAndLength(explicitTag
, tagAndLength
{
603 class
: classContextSpecific
,
605 length
: bodyLen
+ tags
.Len(),
613 // Marshal returns the ASN.1 encoding of val.
615 // In addition to the struct tags recognised by Unmarshal, the following can be
618 // ia5: causes strings to be marshaled as ASN.1, IA5 strings
619 // omitempty: causes empty slices to be skipped
620 // printable: causes strings to be marshaled as ASN.1, PrintableString strings.
621 // utf8: causes strings to be marshaled as ASN.1, UTF8 strings
622 func Marshal(val
interface{}) ([]byte, error
) {
624 v
:= reflect
.ValueOf(val
)
625 f
:= newForkableWriter()
626 err
:= marshalField(f
, v
, fieldParameters
{})
630 _
, err
= f
.writeTo(&out
)
631 return out
.Bytes(), nil