timestamp.go 4.65 KB
Newer Older
1 2 3 4 5
package irma

import (
	"crypto/sha256"
	"encoding/asn1"
6
	gobig "math/big"
7 8

	"github.com/bwesterb/go-atum"
9
	"github.com/go-errors/errors"
10 11
	"github.com/privacybydesign/gabi"
	"github.com/privacybydesign/gabi/big"
12 13 14 15 16
)

// GetTimestamp GETs a signed timestamp (a signature over the current time and the parameters)
// over the message to be signed, the randomized signatures over the attributes, and the disclosed
// attributes, for in attribute-based signature sessions.
17
func GetTimestamp(message string, sigs []*big.Int, disclosed [][]*big.Int, conf *Configuration) (*atum.Timestamp, error) {
18
	nonce, timestampServerUrl, err := TimestampRequest(message, sigs, disclosed, true, conf)
19 20 21 22
	if err != nil {
		return nil, err
	}
	alg := atum.Ed25519
23
	return atum.SendRequest(timestampServerUrl, atum.Request{
24 25 26 27 28 29 30
		Nonce:           nonce,
		PreferredSigAlg: &alg,
	})
}

// TimestampRequest computes the nonce to be signed by a timestamp server, given a message to be signed
// in an attribute-based signature session along with the randomized signatures over the attributes
31 32
// and the disclosed attributes. The url of the timestamp server that should be used to validate the
// request is returned as the second return value.
33
func TimestampRequest(message string, sigs []*big.Int, disclosed [][]*big.Int, new bool, conf *Configuration) (
34
	[]byte, string, error) {
35 36
	msgHash := sha256.Sum256([]byte(message))

37 38 39
	// Convert the sigs and disclosed (double) slices to (double) slices of gobig.Int's for asn1
	sigsint := make([]*gobig.Int, len(sigs))
	for i, k := range sigs {
40
		sigsint[i] = k.Go()
41
	}
42

43
	timestampServerUrl := ""
44 45 46
	disclosedint := make([][]*gobig.Int, len(disclosed))
	dlreps := make([]*gobig.Int, len(disclosed))
	var d interface{} = disclosedint
47
	for i, _ := range disclosed {
48
		meta := MetadataFromInt(disclosed[i][1], conf)
49 50 51
		if meta.CredentialType() == nil {
			return nil, "", errors.New("Cannot compute timestamp request involving unknown credential types")
		}
52 53 54
		if !new {
			disclosedint[i] = make([]*gobig.Int, len(disclosed[i]))
			for j, k := range disclosed[i] {
55
				disclosedint[i][j] = k.Go()
56 57 58
			}
		} else {
			if len(disclosed[i]) < 2 || disclosed[i][1].Cmp(bigZero) == 0 {
59
				return nil, "", errors.Errorf("metadata attribute of credential %d not disclosed", i)
60 61 62
			}
			pk, err := conf.PublicKey(meta.CredentialType().IssuerIdentifier(), meta.KeyCounter())
			if err != nil {
63
				return nil, "", err
64
			}
65
			r, err := gabi.RepresentToPublicKey(pk, disclosed[i])
66
			if err != nil {
67
				return nil, "", err
68
			}
69
			dlreps[i] = r.Go()
70
		}
71 72 73 74 75 76 77 78 79 80 81

		// Determine timestamp server that should be used
		schemeId := meta.CredentialType().SchemeManagerIdentifier()
		tss := conf.SchemeManagers[schemeId].TimestampServer
		if tss == "" {
			return nil, "", errors.Errorf("No timestamp server specified in scheme %s", schemeId.String())
		}
		if timestampServerUrl != "" && timestampServerUrl != tss {
			return nil, "", errors.New("No support for multiple timestamp servers in timestamp format")
		}
		timestampServerUrl = tss
82
	}
83 84 85 86
	if new {
		d = dlreps
	}

87
	bts, err := asn1.Marshal(struct {
88
		Sigs      []*gobig.Int
89
		MsgHash   []byte
90
		Disclosed interface{}
91
	}{
92
		sigsint, msgHash[:], d,
93 94
	})
	if err != nil {
95
		return nil, "", err
96 97 98
	}

	hashed := sha256.Sum256(bts)
99
	return hashed[:], timestampServerUrl, nil
100 101
}

102
// Given an SignedMessage, verify the timestamp over the signed message, disclosed attributes,
103
// and rerandomized CL-signatures.
104
func (sm *SignedMessage) VerifyTimestamp(message string, conf *Configuration) error {
105 106 107
	// Extract the disclosed attributes and randomized CL-signatures from the proofs in order to
	// construct the nonce that should be signed by the timestamp server.
	zero := big.NewInt(0)
108
	size := len(sm.Signature)
109 110
	sigs := make([]*big.Int, size)
	disclosed := make([][]*big.Int, size)
111
	for i, proof := range sm.Signature {
112 113
		proofd := proof.(*gabi.ProofD)
		sigs[i] = proofd.A
114 115 116 117
		ct := MetadataFromInt(proofd.ADisclosed[1], conf).CredentialType()
		if ct == nil {
			return errors.New("Cannot verify timestamp: signature contains attributes from unknown credential type")
		}
118
		attrcount := len(ct.AttributeTypes) + 2 // plus secret key and metadata
119 120 121 122 123 124 125 126 127 128 129
		disclosed[i] = make([]*big.Int, attrcount)
		for j := 0; j < attrcount; j++ {
			val, ok := proofd.ADisclosed[j]
			if !ok {
				disclosed[i][j] = zero
			} else {
				disclosed[i][j] = val
			}
		}
	}

130
	bts, timestampServerUrl, err := TimestampRequest(message, sigs, disclosed, sm.Version() >= 2, conf)
131 132 133
	if err != nil {
		return err
	}
134
	sm.Timestamp.ServerUrl = timestampServerUrl // Timestamp server could be moved to other url
135
	valid, err := sm.Timestamp.Verify(bts)
136 137 138 139 140 141 142 143
	if err != nil {
		return err
	}
	if !valid {
		return errors.New("Timestamp signature invalid")
	}
	return nil
}