...

Source file src/github.com/digitorus/timestamp/timestamp.go

Documentation: github.com/digitorus/timestamp

     1  // Package timestamp implements the Time-Stamp Protocol (TSP) as specified in
     2  // RFC3161 (Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)).
     3  package timestamp
     4  
     5  import (
     6  	"crypto"
     7  	"crypto/rand"
     8  	"crypto/x509"
     9  	"crypto/x509/pkix"
    10  	"encoding/asn1"
    11  	"fmt"
    12  	"io"
    13  	"math/big"
    14  	"strconv"
    15  	"strings"
    16  	"time"
    17  
    18  	"github.com/digitorus/pkcs7"
    19  )
    20  
    21  // FailureInfo contains the failure details of an Time-Stamp request. See
    22  // https://tools.ietf.org/html/rfc3161#section-2.4.2
    23  type FailureInfo int
    24  
    25  const (
    26  	// UnknownFailureInfo mean that no known failure info was provided
    27  	UnknownFailureInfo FailureInfo = -1
    28  	// BadAlgorithm defines an unrecognized or unsupported Algorithm Identifier
    29  	BadAlgorithm FailureInfo = 0
    30  	// BadRequest indicates that the transaction not permitted or supported
    31  	BadRequest FailureInfo = 2
    32  	// BadDataFormat means tha data submitted has the wrong format
    33  	BadDataFormat FailureInfo = 5
    34  	// TimeNotAvailable indicates that TSA's time source is not available
    35  	TimeNotAvailable FailureInfo = 14
    36  	// UnacceptedPolicy indicates that the requested TSA policy is not supported
    37  	// by the TSA
    38  	UnacceptedPolicy FailureInfo = 15
    39  	// UnacceptedExtension indicates that the requested extension is not supported
    40  	// by the TSA
    41  	UnacceptedExtension FailureInfo = 16
    42  	// AddInfoNotAvailable means that the information requested could not be
    43  	// understood or is not available
    44  	AddInfoNotAvailable FailureInfo = 17
    45  	// SystemFailure indicates that the request cannot be handled due to system
    46  	// failure
    47  	SystemFailure FailureInfo = 25
    48  )
    49  
    50  func (f FailureInfo) String() string {
    51  	switch f {
    52  	case BadAlgorithm:
    53  		return "unrecognized or unsupported Algorithm Identifier"
    54  	case BadRequest:
    55  		return "transaction not permitted or supported"
    56  	case BadDataFormat:
    57  		return "the data submitted has the wrong format"
    58  	case TimeNotAvailable:
    59  		return "the TSA's time source is not available"
    60  	case UnacceptedPolicy:
    61  		return "the requested TSA policy is not supported by the TSA"
    62  	case UnacceptedExtension:
    63  		return "the requested extension is not supported by the TSA"
    64  	case AddInfoNotAvailable:
    65  		return "the additional information requested could not be understood or is not available"
    66  	case SystemFailure:
    67  		return "the request cannot be handled due to system failure"
    68  	default:
    69  		return "unknown failure"
    70  	}
    71  }
    72  
    73  // Status contains the status of an Time-Stamp request. See
    74  // https://tools.ietf.org/html/rfc3161#section-2.4.2
    75  type Status int
    76  
    77  const (
    78  	// Granted PKIStatus contains the value zero a TimeStampToken, as requested,
    79  	// is present.
    80  	Granted Status = 0
    81  	// GrantedWithMods PKIStatus contains the value one a TimeStampToken, with
    82  	// modifications, is present.
    83  	GrantedWithMods Status = 1
    84  	// Rejection PKIStatus
    85  	Rejection Status = 2
    86  	// Waiting PKIStatus
    87  	Waiting Status = 3
    88  	// RevocationWarning PKIStatus
    89  	RevocationWarning Status = 4
    90  	// RevocationNotification PKIStatus
    91  	RevocationNotification Status = 5
    92  )
    93  
    94  func (s Status) String() string {
    95  	switch s {
    96  	case Granted:
    97  		return "the request is granted"
    98  	case GrantedWithMods:
    99  		return "the request is granted with modifications"
   100  	case Rejection:
   101  		return "the request is rejected"
   102  	case Waiting:
   103  		return "the request is waiting"
   104  	case RevocationWarning:
   105  		return "revocation is imminent"
   106  	case RevocationNotification:
   107  		return "revocation has occurred"
   108  	default:
   109  		return "unknown status: " + strconv.Itoa(int(s))
   110  	}
   111  }
   112  
   113  // ParseError results from an invalid Time-Stamp request or response.
   114  type ParseError string
   115  
   116  func (p ParseError) Error() string {
   117  	return string(p)
   118  }
   119  
   120  // Request represents an Time-Stamp request. See
   121  // https://tools.ietf.org/html/rfc3161#section-2.4.1
   122  type Request struct {
   123  	HashAlgorithm crypto.Hash
   124  	HashedMessage []byte
   125  
   126  	// Certificates indicates if the TSA needs to return the signing certificate
   127  	// and optionally any other certificates of the chain as part of the response.
   128  	Certificates bool
   129  
   130  	// The TSAPolicyOID field, if provided, indicates the TSA policy under
   131  	// which the TimeStampToken SHOULD be provided
   132  	TSAPolicyOID asn1.ObjectIdentifier
   133  
   134  	// The nonce, if provided, allows the client to verify the timeliness of
   135  	// the response.
   136  	Nonce *big.Int
   137  
   138  	// Extensions contains raw X.509 extensions from the Extensions field of the
   139  	// Time-Stamp request. When parsing requests, this can be used to extract
   140  	// non-critical extensions that are not parsed by this package. When
   141  	// marshaling OCSP requests, the Extensions field is ignored, see
   142  	// ExtraExtensions.
   143  	Extensions []pkix.Extension
   144  
   145  	// ExtraExtensions contains extensions to be copied, raw, into any marshaled
   146  	// OCSP response (in the singleExtensions field). Values override any
   147  	// extensions that would otherwise be produced based on the other fields. The
   148  	// ExtraExtensions field is not populated when parsing Time-Stamp requests,
   149  	// see Extensions.
   150  	ExtraExtensions []pkix.Extension
   151  }
   152  
   153  // ParseRequest parses an timestamp request in DER form.
   154  func ParseRequest(bytes []byte) (*Request, error) {
   155  	var err error
   156  	var rest []byte
   157  	var req request
   158  
   159  	if rest, err = asn1.Unmarshal(bytes, &req); err != nil {
   160  		return nil, err
   161  	}
   162  	if len(rest) > 0 {
   163  		return nil, ParseError("trailing data in Time-Stamp request")
   164  	}
   165  
   166  	if len(req.MessageImprint.HashedMessage) == 0 {
   167  		return nil, ParseError("Time-Stamp request contains no hashed message")
   168  	}
   169  
   170  	hashFunc := getHashAlgorithmFromOID(req.MessageImprint.HashAlgorithm.Algorithm)
   171  	if hashFunc == crypto.Hash(0) {
   172  		return nil, ParseError("Time-Stamp request uses unknown hash function")
   173  	}
   174  
   175  	return &Request{
   176  		HashAlgorithm: hashFunc,
   177  		HashedMessage: req.MessageImprint.HashedMessage,
   178  		Certificates:  req.CertReq,
   179  		Nonce:         req.Nonce,
   180  		TSAPolicyOID:  req.ReqPolicy,
   181  		Extensions:    req.Extensions,
   182  	}, nil
   183  }
   184  
   185  // Marshal marshals the Time-Stamp request to ASN.1 DER encoded form.
   186  func (req *Request) Marshal() ([]byte, error) {
   187  	request := request{
   188  		Version: 1,
   189  		MessageImprint: messageImprint{
   190  			HashAlgorithm: pkix.AlgorithmIdentifier{
   191  				Algorithm: getOIDFromHashAlgorithm(req.HashAlgorithm),
   192  				Parameters: asn1.RawValue{
   193  					Tag: 5, /* ASN.1 NULL */
   194  				},
   195  			},
   196  			HashedMessage: req.HashedMessage,
   197  		},
   198  		CertReq:    req.Certificates,
   199  		Extensions: req.ExtraExtensions,
   200  	}
   201  
   202  	if req.TSAPolicyOID != nil {
   203  		request.ReqPolicy = req.TSAPolicyOID
   204  	}
   205  	if req.Nonce != nil {
   206  		request.Nonce = req.Nonce
   207  	}
   208  	reqBytes, err := asn1.Marshal(request)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  	return reqBytes, nil
   213  }
   214  
   215  // Timestamp represents an Time-Stamp. See:
   216  // https://tools.ietf.org/html/rfc3161#section-2.4.1
   217  type Timestamp struct {
   218  	// Timestamp token part of raw ASN.1 DER content.
   219  	RawToken []byte
   220  
   221  	HashAlgorithm crypto.Hash
   222  	HashedMessage []byte
   223  
   224  	Time         time.Time
   225  	Accuracy     time.Duration
   226  	SerialNumber *big.Int
   227  	Policy       asn1.ObjectIdentifier
   228  	Ordering     bool
   229  	Nonce        *big.Int
   230  	Qualified    bool
   231  
   232  	Certificates []*x509.Certificate
   233  
   234  	// If set to true, includes TSA certificate in timestamp response
   235  	AddTSACertificate bool
   236  
   237  	// Extensions contains raw X.509 extensions from the Extensions field of the
   238  	// Time-Stamp. When parsing time-stamps, this can be used to extract
   239  	// non-critical extensions that are not parsed by this package. When
   240  	// marshaling time-stamps, the Extensions field is ignored, see
   241  	// ExtraExtensions.
   242  	Extensions []pkix.Extension
   243  
   244  	// ExtraExtensions contains extensions to be copied, raw, into any marshaled
   245  	// Time-Stamp response. Values override any extensions that would otherwise
   246  	// be produced based on the other fields. The ExtraExtensions field is not
   247  	// populated when parsing Time-Stamp responses, see Extensions.
   248  	ExtraExtensions []pkix.Extension
   249  }
   250  
   251  // ParseResponse parses an Time-Stamp response in DER form containing a
   252  // TimeStampToken.
   253  //
   254  // Invalid signatures or parse failures will result in a ParseError. Error
   255  // responses will result in a ResponseError.
   256  func ParseResponse(bytes []byte) (*Timestamp, error) {
   257  	var err error
   258  	var rest []byte
   259  	var resp response
   260  
   261  	if rest, err = asn1.Unmarshal(bytes, &resp); err != nil {
   262  		return nil, err
   263  	}
   264  	if len(rest) > 0 {
   265  		return nil, ParseError("trailing data in Time-Stamp response")
   266  	}
   267  
   268  	if resp.Status.Status > 0 {
   269  		var fis string
   270  		fi := resp.Status.FailureInfo()
   271  		if fi != UnknownFailureInfo {
   272  			fis = fi.String()
   273  		}
   274  		return nil, fmt.Errorf("%s: %s (%v)",
   275  			resp.Status.Status.String(),
   276  			strings.Join(resp.Status.StatusString, ","),
   277  			fis)
   278  	}
   279  
   280  	if len(resp.TimeStampToken.Bytes) == 0 {
   281  		return nil, ParseError("no pkcs7 data in Time-Stamp response")
   282  	}
   283  
   284  	return Parse(resp.TimeStampToken.FullBytes)
   285  }
   286  
   287  // Parse parses an Time-Stamp in DER form. If the time-stamp contains a
   288  // certificate then the signature over the response is checked.
   289  //
   290  // Invalid signatures or parse failures will result in a ParseError. Error
   291  // responses will result in a ResponseError.
   292  func Parse(bytes []byte) (*Timestamp, error) {
   293  	var addTSACertificate bool
   294  	p7, err := pkcs7.Parse(bytes)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  
   299  	if len(p7.Certificates) > 0 {
   300  		if err = p7.Verify(); err != nil {
   301  			return nil, err
   302  		}
   303  		addTSACertificate = true
   304  	} else {
   305  		addTSACertificate = false
   306  	}
   307  
   308  	var inf tstInfo
   309  	if _, err = asn1.Unmarshal(p7.Content, &inf); err != nil {
   310  		return nil, err
   311  	}
   312  
   313  	if len(inf.MessageImprint.HashedMessage) == 0 {
   314  		return nil, ParseError("Time-Stamp response contains no hashed message")
   315  	}
   316  
   317  	ret := &Timestamp{
   318  		RawToken:      bytes,
   319  		HashedMessage: inf.MessageImprint.HashedMessage,
   320  		Time:          inf.Time,
   321  		Accuracy: time.Duration((time.Second * time.Duration(inf.Accuracy.Seconds)) +
   322  			(time.Millisecond * time.Duration(inf.Accuracy.Milliseconds)) +
   323  			(time.Microsecond * time.Duration(inf.Accuracy.Microseconds))),
   324  		SerialNumber:      inf.SerialNumber,
   325  		Policy:            inf.Policy,
   326  		Ordering:          inf.Ordering,
   327  		Nonce:             inf.Nonce,
   328  		Certificates:      p7.Certificates,
   329  		AddTSACertificate: addTSACertificate,
   330  		Extensions:        inf.Extensions,
   331  	}
   332  
   333  	ret.HashAlgorithm = getHashAlgorithmFromOID(inf.MessageImprint.HashAlgorithm.Algorithm)
   334  	if ret.HashAlgorithm == crypto.Hash(0) {
   335  		return nil, ParseError("Time-Stamp response uses unknown hash function")
   336  	}
   337  
   338  	if oidInExtensions(asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 3}, inf.Extensions) {
   339  		ret.Qualified = true
   340  	}
   341  	return ret, nil
   342  }
   343  
   344  // RequestOptions contains options for constructing timestamp requests.
   345  type RequestOptions struct {
   346  	// Hash contains the hash function that should be used when
   347  	// constructing the timestamp request. If zero, SHA-256 will be used.
   348  	Hash crypto.Hash
   349  
   350  	// Certificates sets Request.Certificates
   351  	Certificates bool
   352  
   353  	// The TSAPolicyOID field, if provided, indicates the TSA policy under
   354  	// which the TimeStampToken SHOULD be provided
   355  	TSAPolicyOID asn1.ObjectIdentifier
   356  
   357  	// The nonce, if provided, allows the client to verify the timeliness of
   358  	// the response.
   359  	Nonce *big.Int
   360  }
   361  
   362  func (opts *RequestOptions) hash() crypto.Hash {
   363  	if opts == nil || opts.Hash == 0 {
   364  		return crypto.SHA256
   365  	}
   366  	return opts.Hash
   367  }
   368  
   369  // CreateRequest returns a DER-encoded, timestamp request for the status of cert. If
   370  // opts is nil then sensible defaults are used.
   371  func CreateRequest(r io.Reader, opts *RequestOptions) ([]byte, error) {
   372  	hashFunc := opts.hash()
   373  
   374  	if !hashFunc.Available() {
   375  		return nil, x509.ErrUnsupportedAlgorithm
   376  	}
   377  	h := opts.hash().New()
   378  
   379  	b := make([]byte, h.Size())
   380  	for {
   381  		n, err := r.Read(b)
   382  		if err == io.EOF {
   383  			break
   384  		}
   385  
   386  		_, err = h.Write(b[:n])
   387  		if err != nil {
   388  			return nil, fmt.Errorf("failed to create hash")
   389  		}
   390  	}
   391  
   392  	req := &Request{
   393  		HashAlgorithm: opts.hash(),
   394  		HashedMessage: h.Sum(nil),
   395  	}
   396  	if opts != nil {
   397  		req.Certificates = opts.Certificates
   398  	}
   399  	if opts != nil && opts.TSAPolicyOID != nil {
   400  		req.TSAPolicyOID = opts.TSAPolicyOID
   401  	}
   402  	if opts != nil && opts.Nonce != nil {
   403  		req.Nonce = opts.Nonce
   404  	}
   405  	return req.Marshal()
   406  }
   407  
   408  // CreateResponseWithOpts returns a DER-encoded timestamp response with the specified contents.
   409  // The fields in the response are populated as follows:
   410  //
   411  // The responder cert is used to populate the responder's name field, and the
   412  // certificate itself is provided alongside the timestamp response signature.
   413  func (t *Timestamp) CreateResponseWithOpts(signingCert *x509.Certificate, priv crypto.Signer, opts crypto.SignerOpts) ([]byte, error) {
   414  	messageImprint := getMessageImprint(t.HashAlgorithm, t.HashedMessage)
   415  
   416  	tsaSerialNumber, err := generateTSASerialNumber()
   417  	if err != nil {
   418  		return nil, err
   419  	}
   420  	tstInfo, err := t.populateTSTInfo(messageImprint, t.Policy, tsaSerialNumber, signingCert)
   421  	if err != nil {
   422  		return nil, err
   423  	}
   424  	signature, err := t.generateSignedData(tstInfo, priv, signingCert, opts)
   425  	if err != nil {
   426  		return nil, err
   427  	}
   428  	timestampRes := response{
   429  		Status: pkiStatusInfo{
   430  			Status: Granted,
   431  		},
   432  		TimeStampToken: asn1.RawValue{FullBytes: signature},
   433  	}
   434  	tspResponseBytes, err := asn1.Marshal(timestampRes)
   435  	if err != nil {
   436  		return nil, err
   437  	}
   438  	return tspResponseBytes, nil
   439  }
   440  
   441  // CreateResponse returns a DER-encoded timestamp response with the specified contents.
   442  // The fields in the response are populated as follows:
   443  //
   444  // The responder cert is used to populate the responder's name field, and the
   445  // certificate itself is provided alongside the timestamp response signature.
   446  //
   447  // This function is equivalent to CreateResponseWithOpts, using a SHA256 hash.
   448  //
   449  // Deprecated: Use CreateResponseWithOpts instead.
   450  func (t *Timestamp) CreateResponse(signingCert *x509.Certificate, priv crypto.Signer) ([]byte, error) {
   451  	return t.CreateResponseWithOpts(signingCert, priv, crypto.SHA256)
   452  }
   453  
   454  // CreateErrorResponse is used to create response other than granted and granted with mod status
   455  func CreateErrorResponse(pkiStatus Status, pkiFailureInfo FailureInfo) ([]byte, error) {
   456  	var bs asn1.BitString
   457  	setFlag(&bs, int(pkiFailureInfo))
   458  
   459  	timestampRes := response{
   460  		Status: pkiStatusInfo{
   461  			Status:   pkiStatus,
   462  			FailInfo: bs,
   463  		},
   464  	}
   465  	tspResponseBytes, err := asn1.Marshal(timestampRes)
   466  	if err != nil {
   467  		return nil, err
   468  	}
   469  	return tspResponseBytes, nil
   470  }
   471  
   472  func setFlag(bs *asn1.BitString, i int) {
   473  	for l := len(bs.Bytes); l < 4; l++ {
   474  		(*bs).Bytes = append((*bs).Bytes, byte(0))
   475  		(*bs).BitLength = len((*bs).Bytes) * 8
   476  	}
   477  	b := i / 8
   478  	p := uint(7 - (i - 8*b))
   479  	(*bs).Bytes[b] = (*bs).Bytes[b] | (1 << p)
   480  	bs.BitLength = asn1BitLength(bs.Bytes)
   481  	bs.Bytes = bs.Bytes[0 : (bs.BitLength/8)+1]
   482  }
   483  
   484  func getMessageImprint(hashAlgorithm crypto.Hash, hashedMessage []byte) messageImprint {
   485  	messageImprint := messageImprint{
   486  		HashAlgorithm: pkix.AlgorithmIdentifier{
   487  			Algorithm:  getOIDFromHashAlgorithm(hashAlgorithm),
   488  			Parameters: asn1.NullRawValue,
   489  		},
   490  		HashedMessage: hashedMessage,
   491  	}
   492  	return messageImprint
   493  }
   494  
   495  func generateTSASerialNumber() (*big.Int, error) {
   496  	randomBytes := make([]byte, 20)
   497  	_, err := rand.Read(randomBytes)
   498  	if err != nil {
   499  		return nil, err
   500  	}
   501  	serialNumber := big.NewInt(0)
   502  	serialNumber = serialNumber.SetBytes(randomBytes)
   503  	return serialNumber, nil
   504  }
   505  
   506  func (t *Timestamp) populateTSTInfo(messageImprint messageImprint, policyOID asn1.ObjectIdentifier, tsaSerialNumber *big.Int, tsaCert *x509.Certificate) ([]byte, error) {
   507  	dirGeneralName, err := asn1.Marshal(asn1.RawValue{Tag: 4, Class: 2, IsCompound: true, Bytes: tsaCert.RawSubject})
   508  	if err != nil {
   509  		return nil, err
   510  	}
   511  	tstInfo := tstInfo{
   512  		Version:        1,
   513  		Policy:         policyOID,
   514  		MessageImprint: messageImprint,
   515  		SerialNumber:   tsaSerialNumber,
   516  		Time:           t.Time,
   517  		TSA:            asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: dirGeneralName},
   518  		Ordering:       t.Ordering,
   519  	}
   520  	if t.Nonce != nil {
   521  		tstInfo.Nonce = t.Nonce
   522  	}
   523  	if t.Accuracy != 0 {
   524  		if t.Accuracy < time.Microsecond {
   525  			// Round up to 1 microsecond if accuracy is lower than 1 microsecond but greater than 0 nanosecond
   526  			tstInfo.Accuracy.Microseconds = 1
   527  		} else {
   528  			seconds := t.Accuracy.Truncate(time.Second)
   529  			tstInfo.Accuracy.Seconds = int64(seconds.Seconds())
   530  			ms := (t.Accuracy - seconds).Truncate(time.Millisecond)
   531  			if ms != 0 {
   532  				tstInfo.Accuracy.Milliseconds = int64(ms.Milliseconds())
   533  			}
   534  			microSeconds := (t.Accuracy - seconds - ms).Truncate(time.Microsecond)
   535  			if microSeconds != 0 {
   536  				tstInfo.Accuracy.Microseconds = int64(microSeconds.Microseconds())
   537  			}
   538  		}
   539  	}
   540  	if len(t.ExtraExtensions) != 0 {
   541  		tstInfo.Extensions = t.ExtraExtensions
   542  	}
   543  	if t.Qualified && !oidInExtensions(asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 3}, t.ExtraExtensions) {
   544  		qcStatements := []qcStatement{{
   545  			StatementID: asn1.ObjectIdentifier{0, 4, 0, 19422, 1, 1},
   546  		}}
   547  		asn1QcStats, err := asn1.Marshal(qcStatements)
   548  		if err != nil {
   549  			return nil, err
   550  		}
   551  		tstInfo.Extensions = append(tstInfo.Extensions, pkix.Extension{
   552  			Id:       []int{1, 3, 6, 1, 5, 5, 7, 1, 3},
   553  			Value:    asn1QcStats,
   554  			Critical: false,
   555  		})
   556  	}
   557  	tstInfoBytes, err := asn1.Marshal(tstInfo)
   558  	if err != nil {
   559  		return nil, err
   560  	}
   561  	return tstInfoBytes, nil
   562  }
   563  
   564  func (t *Timestamp) populateSigningCertificateV2Ext(certificate *x509.Certificate) ([]byte, error) {
   565  	if !t.HashAlgorithm.Available() {
   566  		return nil, x509.ErrUnsupportedAlgorithm
   567  	}
   568  	if t.HashAlgorithm.HashFunc() == crypto.SHA1 {
   569  		return nil, fmt.Errorf("for SHA1 use ESSCertID instead of ESSCertIDv2")
   570  	}
   571  
   572  	h := t.HashAlgorithm.HashFunc().New()
   573  	_, err := h.Write(certificate.Raw)
   574  	if err != nil {
   575  		return nil, fmt.Errorf("failed to create hash")
   576  	}
   577  
   578  	var hashAlg pkix.AlgorithmIdentifier
   579  
   580  	// HashAlgorithm defaults to SHA256
   581  	if t.HashAlgorithm.HashFunc() != crypto.SHA256 {
   582  		hashAlg = pkix.AlgorithmIdentifier{
   583  			Algorithm:  hashOIDs[t.HashAlgorithm.HashFunc()],
   584  			Parameters: asn1.NullRawValue,
   585  		}
   586  	}
   587  
   588  	signingCertificateV2 := signingCertificateV2{
   589  		Certs: []essCertIDv2{{
   590  			HashAlgorithm: hashAlg,
   591  			CertHash:      h.Sum(nil),
   592  			IssuerSerial: issuerAndSerial{
   593  				IssuerName: generalNames{
   594  					Name: asn1.RawValue{Tag: 4, Class: 2, IsCompound: true, Bytes: certificate.RawIssuer},
   595  				},
   596  				SerialNumber: certificate.SerialNumber,
   597  			},
   598  		}},
   599  	}
   600  	signingCertV2Bytes, err := asn1.Marshal(signingCertificateV2)
   601  	if err != nil {
   602  		return nil, err
   603  	}
   604  	return signingCertV2Bytes, nil
   605  }
   606  
   607  // digestAlgorithmToOID converts the hash func to the corresponding OID.
   608  // This should have parity with [pkcs7.getHashForOID].
   609  func digestAlgorithmToOID(hash crypto.Hash) (asn1.ObjectIdentifier, error) {
   610  	switch hash {
   611  	case crypto.SHA1:
   612  		return pkcs7.OIDDigestAlgorithmSHA1, nil
   613  	case crypto.SHA256:
   614  		return pkcs7.OIDDigestAlgorithmSHA256, nil
   615  	case crypto.SHA384:
   616  		return pkcs7.OIDDigestAlgorithmSHA384, nil
   617  	case crypto.SHA512:
   618  		return pkcs7.OIDDigestAlgorithmSHA512, nil
   619  	}
   620  	return nil, pkcs7.ErrUnsupportedAlgorithm
   621  }
   622  
   623  func (t *Timestamp) generateSignedData(tstInfo []byte, signer crypto.Signer, certificate *x509.Certificate, opts crypto.SignerOpts) ([]byte, error) {
   624  	signedData, err := pkcs7.NewSignedData(tstInfo)
   625  	if err != nil {
   626  		return nil, err
   627  	}
   628  
   629  	alg, err := digestAlgorithmToOID(opts.HashFunc())
   630  	if err != nil {
   631  		return nil, err
   632  	}
   633  	signedData.SetDigestAlgorithm(alg)
   634  	signedData.SetContentType(asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4})
   635  	signedData.GetSignedData().Version = 3
   636  
   637  	signingCertV2Bytes, err := t.populateSigningCertificateV2Ext(certificate)
   638  	if err != nil {
   639  		return nil, err
   640  	}
   641  
   642  	signerInfoConfig := pkcs7.SignerInfoConfig{
   643  		ExtraSignedAttributes: []pkcs7.Attribute{
   644  			{
   645  				Type:  asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 47},
   646  				Value: asn1.RawValue{FullBytes: signingCertV2Bytes},
   647  			},
   648  		},
   649  	}
   650  	if !t.AddTSACertificate {
   651  		signerInfoConfig.SkipCertificates = true
   652  	}
   653  
   654  	if len(t.Certificates) > 0 {
   655  		err = signedData.AddSignerChain(certificate, signer, t.Certificates, signerInfoConfig)
   656  	} else {
   657  		err = signedData.AddSigner(certificate, signer, signerInfoConfig)
   658  	}
   659  	if err != nil {
   660  		return nil, err
   661  	}
   662  
   663  	signature, err := signedData.Finish()
   664  	if err != nil {
   665  		return nil, err
   666  	}
   667  	return signature, nil
   668  }
   669  
   670  // copied from crypto/x509 package
   671  // oidNotInExtensions reports whether an extension with the given oid exists in
   672  // extensions.
   673  func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool {
   674  	for _, e := range extensions {
   675  		if e.Id.Equal(oid) {
   676  			return true
   677  		}
   678  	}
   679  	return false
   680  }
   681  

View as plain text