github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/smime/parse.go (about)

     1  package smime
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/asn1"
     6  	"fmt"
     7  
     8  	"github.com/egonelbre/exp/smime/ber"
     9  )
    10  
    11  // RFC 5652 12.1
    12  // -- Content Type Object Identifiers
    13  //
    14  // id-ct-contentInfo OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    15  //     us(840) rsadsi(113549) pkcs(1) pkcs9(9) smime(16) ct(1) 6 }
    16  //
    17  // id-data OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    18  //     us(840) rsadsi(113549) pkcs(1) pkcs7(7) 1 }
    19  //
    20  // id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    21  //     us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
    22  //
    23  // id-envelopedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    24  //     us(840) rsadsi(113549) pkcs(1) pkcs7(7) 3 }
    25  //
    26  // id-digestedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    27  //     us(840) rsadsi(113549) pkcs(1) pkcs7(7) 5 }
    28  //
    29  // id-encryptedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    30  //     us(840) rsadsi(113549) pkcs(1) pkcs7(7) 6 }
    31  //
    32  // id-ct-authData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    33  //     us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1) 2 }
    34  var (
    35  	oidContentInfo = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 6}
    36  
    37  	oidData          = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
    38  	oidSignedData    = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2}
    39  	oidEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3}
    40  	oidDigestedData  = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 5}
    41  	oidEncryptedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 6}
    42  	oidAuthData      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 2}
    43  )
    44  
    45  type Data []byte
    46  
    47  func Parse(data []byte) (ret interface{}, err error) {
    48  	d := ber.NewDecoder(bytes.NewReader(data))
    49  	tree, err := ber.ParseTree(d)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	//pp(tree)
    55  
    56  	// RFC 5652, 3
    57  	// ContentInfo ::= SEQUENCE {
    58  	//    contentType ContentType,
    59  	//    content [0] EXPLICIT ANY DEFINED BY contentType }
    60  	//
    61  	// ContentType ::= OBJECT IDENTIFIER
    62  
    63  	var contentType asn1.ObjectIdentifier
    64  	var content *ber.Tree
    65  
    66  	err = ber.Sequence{
    67  		ber.Check{ber.Universal, ber.TagObjectIdentifier, ber.ObjectIdentifier{&contentType}},
    68  		ber.Check{ber.Context, 0, ber.Explicit{ber.RawTree{&content}}},
    69  	}.Unmarshal(tree)
    70  	if err != nil {
    71  		return
    72  	}
    73  
    74  	switch {
    75  	case oidData.Equal(contentType):
    76  		bytes, err := content.AsOctetString()
    77  		return Data(bytes), err
    78  	case oidSignedData.Equal(contentType):
    79  		ret, err := parseSignedData(content)
    80  		return ret, err
    81  	case oidEnvelopedData.Equal(contentType):
    82  		return nil, fmt.Errorf("enveloped-data not suppoerted")
    83  	case oidDigestedData.Equal(contentType):
    84  		return nil, fmt.Errorf("digested-data not supported")
    85  	case oidEncryptedData.Equal(contentType):
    86  		return nil, fmt.Errorf("encrypted-data not supported")
    87  	case oidAuthData.Equal(contentType):
    88  		return nil, fmt.Errorf("auth-data not supported")
    89  	}
    90  	return nil, fmt.Errorf("unknown content type")
    91  }