...

Source file src/github.com/sassoftware/relic/lib/pkcs9/tsclient/tsclient.go

Documentation: github.com/sassoftware/relic/lib/pkcs9/tsclient

     1  // Copyright © SAS Institute Inc.
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  //     http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package tsclient
    15  
    16  import (
    17  	"context"
    18  	"crypto/tls"
    19  	"errors"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"log"
    23  	"net/http"
    24  	"time"
    25  
    26  	"github.com/sassoftware/relic/config"
    27  	"github.com/sassoftware/relic/lib/pkcs7"
    28  	"github.com/sassoftware/relic/lib/pkcs9"
    29  	"github.com/sassoftware/relic/lib/pkcs9/ratelimit"
    30  	"github.com/sassoftware/relic/lib/pkcs9/timestampcache"
    31  	"github.com/sassoftware/relic/lib/x509tools"
    32  )
    33  
    34  type tsClient struct {
    35  	conf   *config.TimestampConfig
    36  	client *http.Client
    37  }
    38  
    39  func New(conf *config.TimestampConfig) (t pkcs9.Timestamper, err error) {
    40  	tlsconf := &tls.Config{}
    41  	if err := x509tools.LoadCertPool(conf.CaCert, tlsconf); err != nil {
    42  		return nil, err
    43  	}
    44  	client := &http.Client{
    45  		Timeout: time.Second * time.Duration(conf.Timeout),
    46  		Transport: &http.Transport{
    47  			TLSClientConfig: tlsconf,
    48  		},
    49  	}
    50  	t = tsClient{conf, client}
    51  	if conf.RateLimit != 0 {
    52  		t = ratelimit.New(t, conf.RateLimit, conf.RateBurst)
    53  	}
    54  	if len(conf.Memcache) != 0 {
    55  		t, err = timestampcache.New(t, conf.Memcache)
    56  		if err != nil {
    57  			return nil, err
    58  		}
    59  	}
    60  	return
    61  }
    62  
    63  func (c tsClient) Timestamp(ctx context.Context, req *pkcs9.Request) (*pkcs7.ContentInfoSignedData, error) {
    64  	var urls []string
    65  	if req.Legacy {
    66  		urls = c.conf.MsURLs
    67  		if len(urls) == 0 {
    68  			return nil, errors.New("timestamp.msurls is empty")
    69  		}
    70  	} else {
    71  		urls = c.conf.URLs
    72  		if len(urls) == 0 {
    73  			return nil, errors.New("timestamp.urls is empty")
    74  		}
    75  	}
    76  	imprint := req.EncryptedDigest
    77  	if !req.Legacy {
    78  		d := req.Hash.New()
    79  		d.Write(imprint)
    80  		imprint = d.Sum(nil)
    81  	}
    82  	var err error
    83  	for _, url := range urls {
    84  		if err != nil {
    85  			log.Printf("warning: timestamping failed: %s\n  trying next server %s...\n", err, url)
    86  		}
    87  		var token *pkcs7.ContentInfoSignedData
    88  		token, err = c.do(ctx, url, req, imprint)
    89  		if err == nil {
    90  			return token, nil
    91  		}
    92  	}
    93  	return nil, fmt.Errorf("timestamping failed: %s", err)
    94  }
    95  
    96  func (c tsClient) do(ctx context.Context, url string, req *pkcs9.Request, imprint []byte) (*pkcs7.ContentInfoSignedData, error) {
    97  	var msg *pkcs9.TimeStampReq
    98  	var httpReq *http.Request
    99  	var err error
   100  	if !req.Legacy {
   101  		msg, httpReq, err = pkcs9.NewRequest(url, req.Hash, imprint)
   102  	} else {
   103  		httpReq, err = pkcs9.NewLegacyRequest(url, imprint)
   104  	}
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	httpReq.Header.Set("User-Agent", config.UserAgent)
   109  	resp, err := c.client.Do(httpReq.WithContext(ctx))
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	body, err := ioutil.ReadAll(resp.Body)
   114  	resp.Body.Close()
   115  	if err != nil {
   116  		return nil, err
   117  	} else if resp.StatusCode != 200 {
   118  		return nil, fmt.Errorf("%s: HTTP %s\n%s", url, resp.Status, body)
   119  	}
   120  	if req.Legacy {
   121  		return pkcs9.ParseLegacyResponse(body)
   122  	}
   123  	return msg.ParseResponse(body)
   124  }
   125  

View as plain text