requests.go 5.5 KB
Newer Older
1 2 3 4 5
package irmago

import (
	"crypto/sha256"
	"encoding/asn1"
Sietse Ringers's avatar
Sietse Ringers committed
6
	"errors"
7 8 9 10 11 12
	"fmt"
	"log"
	"math/big"
	"strconv"
	"time"

Sietse Ringers's avatar
Sietse Ringers committed
13 14
	"github.com/mhe/gabi"
)
15

Sietse Ringers's avatar
Sietse Ringers committed
16
// SessionRequest contains the context and nonce for an IRMA session.
17 18 19 20 21
type SessionRequest struct {
	Context *big.Int `json:"nonce"`
	Nonce   *big.Int `json:"context"`
}

Sietse Ringers's avatar
Sietse Ringers committed
22
// A DisclosureRequest is a request to disclose certain attributes.
23 24 25 26 27
type DisclosureRequest struct {
	SessionRequest
	Content AttributeDisjunctionList `json:"content"`
}

Sietse Ringers's avatar
Sietse Ringers committed
28
// A SignatureRequest is a a request to sign a message with certain attributes.
29 30 31 32 33 34
type SignatureRequest struct {
	DisclosureRequest
	Message     string `json:"message"`
	MessageType string `json:"messageType"`
}

Sietse Ringers's avatar
Sietse Ringers committed
35 36
// An IssuanceRequest is a request to issue certain credentials,
// optionally also asking for certain attributes to be simultaneously disclosed.
37 38
type IssuanceRequest struct {
	SessionRequest
Sietse Ringers's avatar
Sietse Ringers committed
39
	Credentials []*CredentialRequest     `json:"credentials"`
40
	Disclose    AttributeDisjunctionList `json:"disclose"`
Sietse Ringers's avatar
Sietse Ringers committed
41 42

	state *issuanceState
43 44
}

Sietse Ringers's avatar
Sietse Ringers committed
45 46
// A CredentialRequest contains the attributes and metadata of a credential
// that will be issued in an IssuanceRequest.
47
type CredentialRequest struct {
Sietse Ringers's avatar
Sietse Ringers committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61
	Validity   *Timestamp                `json:"validity"`
	KeyCounter int                       `json:"keyCounter"`
	Credential *CredentialTypeIdentifier `json:"credential"`
	Attributes map[string]string         `json:"attributes"`
}

// Timestamp is a time.Time that marshals to Unix timestamps.
type Timestamp time.Time

type issuanceState struct {
	nonce2   *big.Int
	builders []*gabi.CredentialBuilder
}

Sietse Ringers's avatar
Sietse Ringers committed
62
// AttributeList returns the list of attributes from this credential request.
Sietse Ringers's avatar
Sietse Ringers committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
func (cr *CredentialRequest) AttributeList() (*AttributeList, error) {
	meta := NewMetadataAttribute()
	meta.setKeyCounter(cr.KeyCounter)
	meta.setCredentialTypeIdentifier(cr.Credential.String())
	meta.setSigningDate()
	err := meta.setExpiryDate(cr.Validity)
	if err != nil {
		return nil, err
	}

	attrs := make([]*big.Int, len(cr.Attributes)+1, len(cr.Attributes)+1)
	credtype := MetaStore.Credentials[*cr.Credential]
	if credtype == nil {
		return nil, errors.New("Unknown credential type")
	}
	if len(credtype.Attributes) != len(cr.Attributes) {
		return nil, errors.New("Received unexpected amount of attributes")
	}

	attrs[0] = meta.Int
	for i, attrtype := range credtype.Attributes {
		if str, present := cr.Attributes[attrtype.ID]; present {
			attrs[i+1] = new(big.Int).SetBytes([]byte(str))
		} else {
			return nil, errors.New("Unknown attribute")
		}
	}

	return NewAttributeListFromInts(attrs), nil
}

Sietse Ringers's avatar
Cleanup  
Sietse Ringers committed
94
func newIssuanceState() (*issuanceState, error) {
Sietse Ringers's avatar
Sietse Ringers committed
95 96 97 98 99 100 101 102
	nonce2, err := gabi.RandomBigInt(gabi.DefaultSystemParameters[4096].Lstatzk)
	if err != nil {
		return nil, err
	}
	return &issuanceState{
		nonce2:   nonce2,
		builders: []*gabi.CredentialBuilder{},
	}, nil
103 104
}

Sietse Ringers's avatar
Sietse Ringers committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
// DisjunctionList returns the attributes that must be disclosed in this issuance session.
func (ir *IssuanceRequest) DisjunctionList() AttributeDisjunctionList { return ir.Disclose }

// GetContext returns the context of this session.
func (ir *IssuanceRequest) GetContext() *big.Int { return ir.Context }

// SetContext sets the context of this session.
func (ir *IssuanceRequest) SetContext(context *big.Int) { ir.Context = context }

// GetNonce returns the nonce of this session.
func (ir *IssuanceRequest) GetNonce() *big.Int { return ir.Nonce }

// SetNonce sets the nonce of this session.
func (ir *IssuanceRequest) SetNonce(nonce *big.Int) { ir.Nonce = nonce }

// DisjunctionList returns the attributes to be disclosed in this session.
Sietse Ringers's avatar
Sietse Ringers committed
121
func (dr *DisclosureRequest) DisjunctionList() AttributeDisjunctionList { return dr.Content }
Sietse Ringers's avatar
Sietse Ringers committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148

// GetContext returns the context of this session.
func (dr *DisclosureRequest) GetContext() *big.Int { return dr.Context }

// SetContext sets the context of this session.
func (dr *DisclosureRequest) SetContext(context *big.Int) { dr.Context = context }

// GetNonce returns the nonce of this session.
func (dr *DisclosureRequest) GetNonce() *big.Int { return dr.Nonce }

// SetNonce sets the nonce of this session.
func (dr *DisclosureRequest) SetNonce(nonce *big.Int) { dr.Nonce = nonce }

// DisjunctionList returns the attributes with which the message must be signed.
func (sr *SignatureRequest) DisjunctionList() AttributeDisjunctionList { return sr.Content }

// GetContext returns the context of this session.
func (sr *SignatureRequest) GetContext() *big.Int { return sr.Context }

// SetContext sets the context of this session.
func (sr *SessionRequest) SetContext(context *big.Int) { sr.Context = context }

// SetNonce sets the nonce of this session.
func (sr *SessionRequest) SetNonce(nonce *big.Int) { sr.Nonce = nonce }

// GetNonce returns the nonce of this signature session
// (with the message already hashed into it).
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
func (sr *SignatureRequest) GetNonce() *big.Int {
	hashbytes := sha256.Sum256([]byte(sr.Message))
	hashint := new(big.Int).SetBytes(hashbytes[:])
	// TODO the 2 should be abstracted away
	asn1bytes, err := asn1.Marshal([]interface{}{big.NewInt(2), sr.Nonce, hashint})
	if err != nil {
		log.Print(err) // TODO? does this happen?
	}
	asn1hash := sha256.Sum256(asn1bytes)
	return new(big.Int).SetBytes(asn1hash[:])
}

// MarshalJSON marshals a timestamp.
func (t *Timestamp) MarshalJSON() ([]byte, error) {
	ts := time.Time(*t).Unix()
	stamp := fmt.Sprint(ts)
	return []byte(stamp), nil
}

// UnmarshalJSON unmarshals a timestamp.
func (t *Timestamp) UnmarshalJSON(b []byte) error {
	ts, err := strconv.Atoi(string(b))
	if err != nil {
		return err
	}
	*t = Timestamp(time.Unix(int64(ts), 0))
	return nil
}