github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/ber/marshaling.go (about) 1 /* 2 Example how you would translate the ASN1 spec 3 4 SignerInfo ::= SEQUENCE { 5 version CMSVersion, 6 sid SignerIdentifier, 7 digestAlgorithm DigestAlgorithmIdentifier, 8 signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, 9 signatureAlgorithm SignatureAlgorithmIdentifier, 10 signature SignatureValue, 11 unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL } 12 13 SignerIdentifier ::= CHOICE { 14 issuerAndSerialNumber IssuerAndSerialNumber, 15 subjectKeyIdentifier [0] SubjectKeyIdentifier } 16 17 SignatureValue ::= OCTET STRING 18 19 type asnSignerInfo struct { 20 Version int64 21 Issuer asnIssuerAndSerialNumber 22 SubjectKeyId []byte 23 DigestAlgorithm pkix.AlgorithmIdentifier 24 SignedAttrs asnAttributeSet 25 SignatureAlgorithm pkix.AlgorithmIdentifier 26 Signature []byte 27 UnsignedAttrs asnAttributeSet 28 } 29 30 func (d *asnSignerInfo) marshaler() ber.Marshaler { 31 return ber.Sequence{ 32 ber.Check{ber.Universal, ber.TagInteger, ber.Int64{&d.Version}}, 33 ber.Choice{ 34 ber.Check{ber.Universal, ber.TagSequence, &d.Issuer}, 35 ber.Check{ber.Context, 0, ber.OctetString{&d.SubjectKeyId}}, 36 }, 37 ber.Check{ber.Universal, ber.TagSequence, (*asnAlgorithmIdentifier)(&d.DigestAlgorithm)}, 38 ber.Optional{ber.Check{ber.Context, 0, &d.SignedAttrs}}, 39 ber.Check{ber.Universal, ber.TagSequence, (*asnAlgorithmIdentifier)(&d.SignatureAlgorithm)}, 40 ber.Check{ber.Universal, ber.TagOctetString, ber.OctetString{&d.Signature}}, 41 ber.Optional{ber.Check{ber.Context, 1, &d.UnsignedAttrs}}, 42 } 43 } 44 45 func (d *asnSignerInfo) Unmarshal(tree *ber.Tree) error { return d.marshaler().Unmarshal(tree) } 46 func (d *asnSignerInfo) Marshal() (*ber.Tree, error) { return d.marshaler().Marshal() } 47 */ 48 49 package ber 50 51 // http://play.golang.org/p/MdL7k8-5ER 52 53 import ( 54 "encoding/asn1" 55 "errors" 56 "fmt" 57 "math/big" 58 ) 59 60 // TODO: Optional/Check/Explicit should be all be a single type, 61 // otherwise it's hard to make them work nicely with nesting 62 63 type Marshaler interface { 64 Marshal() (*Tree, error) 65 Unmarshal(*Tree) error 66 } 67 68 type RawTree struct { 69 Tree **Tree 70 } 71 72 func (m RawTree) Unmarshal(tree *Tree) error { 73 *m.Tree = tree 74 return nil 75 } 76 77 func (m RawTree) Marshal() (*Tree, error) { 78 return *m.Tree, nil 79 } 80 81 type DER struct { 82 V *[]byte 83 } 84 85 func (m DER) Unmarshal(tree *Tree) (err error) { 86 *m.V, err = EncodeTree(tree) 87 return 88 } 89 90 func (m DER) Marshal() (*Tree, error) { 91 return DecodeTree(*m.V) 92 } 93 94 type ASN1RawValue struct { 95 V *asn1.RawValue 96 } 97 98 func (m ASN1RawValue) Unmarshal(tree *Tree) (err error) { 99 var data []byte 100 if data, err = EncodeTree(tree); err != nil { 101 return 102 } 103 104 _, err = asn1.Unmarshal(data, m.V) 105 return 106 } 107 108 func (m ASN1RawValue) Marshal() (*Tree, error) { 109 return ASN1Tree(m.V) 110 } 111 112 type Check struct { 113 Class int 114 Tag int 115 Sub Marshaler 116 } 117 118 func (m Check) Unmarshal(tree *Tree) (err error) { 119 if tree.Class != m.Class || tree.Tag != m.Tag { 120 return fmt.Errorf("class/tag doesn't match: got %d/%d expected %d/%d", tree.Class, tree.Tag, m.Class, m.Tag) 121 } 122 return m.Sub.Unmarshal(tree) 123 } 124 125 func (m Check) Marshal() (*Tree, error) { 126 tree, err := m.Sub.Marshal() 127 if err != nil { 128 return nil, err 129 } 130 131 tree.Class = m.Class 132 tree.Tag = m.Tag 133 return tree, nil 134 } 135 136 type Sequence []Marshaler 137 138 func (s Sequence) Unmarshal(tree *Tree) (err error) { 139 children := tree.Children 140 141 var si, ti int 142 for si < len(s) { 143 m := s[si] 144 if opt, ok := m.(Optional); ok { 145 if ti >= len(children) { 146 si += 1 147 continue 148 } 149 150 switch optsub := opt.Sub.(type) { 151 case Check: 152 sub := children[ti] 153 if optsub.Class == sub.Class && optsub.Tag == sub.Tag { 154 if err = optsub.Sub.Unmarshal(sub); err != nil { 155 return 156 } 157 ti += 1 158 } 159 si += 1 160 default: 161 if err = optsub.Unmarshal(children[ti]); err != nil { 162 return 163 } 164 ti += 1 165 si += 1 166 } 167 } else { 168 if ti >= len(children) { 169 return fmt.Errorf("not enough children in tree") 170 } 171 172 sub := children[ti] 173 if err = m.Unmarshal(sub); err != nil { 174 return 175 } 176 177 ti += 1 178 si += 1 179 } 180 } 181 return 182 } 183 184 func (s Sequence) Marshal() (root *Tree, err error) { 185 root = &Tree{ 186 Token: &Token{ 187 Kind: Constructed, 188 Class: Universal, 189 Tag: TagSequence, 190 }, 191 } 192 193 var sub *Tree 194 for _, m := range s { 195 if sub, err = m.Marshal(); err != nil { 196 return 197 } 198 if _, optional := m.(Optional); optional && sub == nil { 199 // we can safely skip this 200 } else { 201 if sub == nil { 202 err = errors.New("marshaling returned nil") 203 return 204 } 205 root.Children = append(root.Children, sub) 206 } 207 } 208 return 209 } 210 211 type Choice []Marshaler 212 213 func (s Choice) Unmarshal(tree *Tree) (err error) { 214 for _, m := range s { 215 check, ok := m.(Check) 216 if !ok { 217 return fmt.Errorf("choice sequence doesn't contain check") 218 } 219 220 if check.Class == tree.Class && check.Tag == tree.Tag { 221 err = check.Unmarshal(tree) 222 return 223 } 224 } 225 226 return fmt.Errorf("applicable choice element not found") 227 } 228 229 func (s Choice) Marshal() (*Tree, error) { 230 // is there a way to handle this? 231 panic("choice shoudln't be used while marshaling") 232 return nil, nil 233 } 234 235 type Optional struct { 236 Sub Marshaler 237 } 238 239 func (m Optional) Unmarshal(tree *Tree) (err error) { 240 return m.Sub.Unmarshal(tree) 241 } 242 243 func isExplicit(s Marshaler) bool { 244 _, ok := s.(Explicit) 245 return ok 246 } 247 248 func isZero(tree *Tree) bool { 249 return (tree == nil) || 250 (tree.Kind == Value && len(tree.Bytes) == 0) || 251 (tree.Kind == Constructed && len(tree.Children) == 0) 252 } 253 254 func (m Optional) Marshal() (tree *Tree, err error) { 255 if tree, err = m.Sub.Marshal(); err != nil { 256 return 257 } 258 259 if isZero(tree) { 260 return nil, nil 261 } else if isExplicit(m.Sub) && isZero(tree.Children[0]) { 262 return nil, nil 263 } 264 return 265 } 266 267 type Explicit struct { 268 Sub Marshaler 269 } 270 271 func (m Explicit) Unmarshal(tree *Tree) (err error) { 272 if len(tree.Children) != 1 { 273 return fmt.Errorf("not enough values for explicit type") 274 } 275 return m.Sub.Unmarshal(tree.Children[0]) 276 } 277 278 func (m Explicit) Marshal() (tree *Tree, err error) { 279 var sub *Tree 280 if sub, err = m.Sub.Marshal(); err != nil { 281 return 282 } 283 tree = &Tree{ 284 Token: &Token{ 285 Kind: Constructed, 286 Class: Context, 287 Tag: 0, 288 }, 289 Children: []*Tree{sub}, 290 } 291 return 292 } 293 294 // TYPES 295 296 type OctetString struct { 297 V *[]byte 298 } 299 300 func (m OctetString) Unmarshal(tree *Tree) error { 301 val, err := tree.AsOctetString() 302 *m.V = val 303 return err 304 } 305 306 func (m OctetString) Marshal() (*Tree, error) { 307 return &Tree{ 308 Token: &Token{ 309 Kind: Value, 310 Class: Universal, 311 Tag: TagOctetString, 312 Bytes: *m.V, 313 }, 314 }, nil 315 } 316 317 type Int64 struct { 318 V *int64 319 } 320 321 func (m Int64) Unmarshal(tree *Tree) error { 322 val, err := tree.AsInt64() 323 *m.V = val 324 return err 325 } 326 327 func (m Int64) Marshal() (*Tree, error) { 328 return ASN1Tree(m.V) 329 } 330 331 type BigInt struct { 332 V **big.Int 333 } 334 335 func (m BigInt) Unmarshal(tree *Tree) error { 336 val, err := tree.AsBigInt() 337 *m.V = val 338 return err 339 } 340 func (m BigInt) Marshal() (*Tree, error) { 341 return ASN1Tree(m.V) 342 } 343 344 type ObjectIdentifier struct { 345 V *asn1.ObjectIdentifier 346 } 347 348 func (m ObjectIdentifier) Unmarshal(tree *Tree) error { 349 val, err := tree.AsObjectIdentifier() 350 *m.V = val 351 return err 352 } 353 func (m ObjectIdentifier) Marshal() (*Tree, error) { 354 return ASN1Tree(m.V) 355 } 356 357 func ASN1Tree(v interface{}) (*Tree, error) { 358 bytes, err := asn1.Marshal(v) 359 if err != nil { 360 return nil, err 361 } 362 return DecodeTree(bytes) 363 }