requests.go 29.7 KB
Newer Older
1
package irma
2 3

import (
4
	"encoding/json"
5
	"encoding/xml"
6
	"fmt"
7
	"io/ioutil"
8 9 10
	"strconv"
	"time"

11
	"github.com/bwesterb/go-atum"
12
	"github.com/dgrijalva/jwt-go"
Sietse Ringers's avatar
Sietse Ringers committed
13
	"github.com/go-errors/errors"
14
	"github.com/privacybydesign/gabi"
15
	"github.com/privacybydesign/gabi/big"
16
	"github.com/privacybydesign/gabi/revocation"
17
	"github.com/privacybydesign/irmago/internal/fs"
Sietse Ringers's avatar
Sietse Ringers committed
18
)
19

20 21 22 23
const (
	LDContextDisclosureRequest = "https://irma.app/ld/request/disclosure/v2"
	LDContextSignatureRequest  = "https://irma.app/ld/request/signature/v2"
	LDContextIssuanceRequest   = "https://irma.app/ld/request/issuance/v2"
24
	LDContextRevocationRequest = "https://irma.app/ld/request/revocation/v1"
25 26
)

Sietse Ringers's avatar
Sietse Ringers committed
27 28
// BaseRequest contains information used by all IRMA session types, such the context and nonce,
// and revocation information.
29
type BaseRequest struct {
30
	LDContext string `json:"@context,omitempty"`
31

Sietse Ringers's avatar
Sietse Ringers committed
32 33 34 35 36 37
	// Set by the IRMA server during the session
	Context         *big.Int         `json:"context,omitempty"`
	Nonce           *big.Int         `json:"nonce,omitempty"`
	ProtocolVersion *ProtocolVersion `json:"protocolVersion,omitempty"`

	// Revocation is set by the requestor to indicate that it requires nonrevocation proofs for the
38
	// specified credential types.
39
	Revocation []CredentialTypeIdentifier `json:"revocation,omitempty"`
Sietse Ringers's avatar
Sietse Ringers committed
40 41
	// RevocationUpdates contains revocation update messages for the client to update its
	// revocation state.
42
	RevocationUpdates map[CredentialTypeIdentifier]map[uint]*revocation.Update `json:"revocationUpdates,omitempty"`
43

44 45 46 47
	ids *IrmaIdentifierSet // cache for Identifiers() method

	legacy bool   // Whether or not this was deserialized from a legacy (pre-condiscon) request
	Type   Action `json:"type,omitempty"` // Session type, only used in legacy code
48 49

	ClientReturnURL string `json:"clientReturnUrl,omitempty"` // URL to proceed to when IRMA session is completed
Sietse Ringers's avatar
Sietse Ringers committed
50 51
}

52 53
// An AttributeCon is only satisfied if all of its containing attribute requests are satisfied.
type AttributeCon []AttributeRequest
54

55 56
// An AttributeDisCon is satisfied if at least one of its containing AttributeCon is satisfied.
type AttributeDisCon []AttributeCon
57

58 59
// AttributeConDisCon is only satisfied if all of the containing AttributeDisCon are satisfied.
type AttributeConDisCon []AttributeDisCon
60

61 62
// A DisclosureRequest is a request to disclose certain attributes. Construct new instances using
// NewDisclosureRequest().
63
type DisclosureRequest struct {
64
	BaseRequest
65

66 67
	Disclose AttributeConDisCon       `json:"disclose,omitempty"`
	Labels   map[int]TranslatedString `json:"labels,omitempty"`
68 69
}

70 71
// A SignatureRequest is a a request to sign a message with certain attributes. Construct new
// instances using NewSignatureRequest().
72
type SignatureRequest struct {
73
	DisclosureRequest
74
	Message string `json:"message"`
75 76
}

Sietse Ringers's avatar
Sietse Ringers committed
77
// An IssuanceRequest is a request to issue certain credentials,
78 79
// optionally also asking for certain attributes to be simultaneously disclosed. Construct new
// instances using NewIssuanceRequest().
80
type IssuanceRequest struct {
81
	DisclosureRequest
82
	Credentials []*CredentialRequest `json:"credentials"`
Tomas's avatar
Tomas committed
83 84 85

	// Derived data
	CredentialInfoList        CredentialInfoList `json:",omitempty"`
86
	RemovalCredentialInfoList CredentialInfoList `json:",omitempty"`
87 88
}

Sietse Ringers's avatar
Sietse Ringers committed
89 90
// A CredentialRequest contains the attributes and metadata of a credential
// that will be issued in an IssuanceRequest.
91
type CredentialRequest struct {
92
	Validity         *Timestamp               `json:"validity,omitempty"`
93
	KeyCounter       uint                     `json:"keyCounter,omitempty"`
94 95
	CredentialTypeID CredentialTypeIdentifier `json:"credential"`
	Attributes       map[string]string        `json:"attributes"`
96
	RevocationKey    string                   `json:"revocationKey,omitempty"`
Sietse Ringers's avatar
Sietse Ringers committed
97 98
}

99 100 101 102
// SessionRequest instances contain all information the irmaclient needs to perform an IRMA session.
type SessionRequest interface {
	Validator
	Base() *BaseRequest
103
	GetNonce(timestamp *atum.Timestamp) *big.Int
104 105 106
	Disclosure() *DisclosureRequest
	Identifiers() *IrmaIdentifierSet
	Action() Action
107
	Legacy() (SessionRequest, error)
108 109 110 111 112
}

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

Sietse Ringers's avatar
Sietse Ringers committed
113 114 115 116 117 118 119
// ServerJwt contains standard JWT fields.
type ServerJwt struct {
	Type       string    `json:"sub"`
	ServerName string    `json:"iss"`
	IssuedAt   Timestamp `json:"iat"`
}

120 121
// RequestorBaseRequest contains fields present in all RequestorRequest types
// with which the requestor configures an IRMA session.
122
type RequestorBaseRequest struct {
Sietse Ringers's avatar
Sietse Ringers committed
123 124
	ResultJwtValidity int    `json:"validity,omitempty"`    // Validity of session result JWT in seconds
	ClientTimeout     int    `json:"timeout,omitempty"`     // Wait this many seconds for the IRMA app to connect before the session times out
125
	CallbackURL       string `json:"callbackUrl,omitempty"` // URL to post session result to
126 127
}

128 129
// RequestorRequest is the message with which requestors start an IRMA session. It contains a
// SessionRequest instance for the irmaclient along with extra fields in a RequestorBaseRequest.
130 131 132
type RequestorRequest interface {
	Validator
	SessionRequest() SessionRequest
133
	Base() RequestorBaseRequest
134 135
}

Sietse Ringers's avatar
Sietse Ringers committed
136 137
// A ServiceProviderRequest contains a disclosure request.
type ServiceProviderRequest struct {
138
	RequestorBaseRequest
Sietse Ringers's avatar
Sietse Ringers committed
139 140 141 142 143
	Request *DisclosureRequest `json:"request"`
}

// A SignatureRequestorRequest contains a signing request.
type SignatureRequestorRequest struct {
144
	RequestorBaseRequest
Sietse Ringers's avatar
Sietse Ringers committed
145 146 147 148 149
	Request *SignatureRequest `json:"request"`
}

// An IdentityProviderRequest contains an issuance request.
type IdentityProviderRequest struct {
150
	RequestorBaseRequest
Sietse Ringers's avatar
Sietse Ringers committed
151 152 153 154 155 156
	Request *IssuanceRequest `json:"request"`
}

// ServiceProviderJwt is a requestor JWT for a disclosure session.
type ServiceProviderJwt struct {
	ServerJwt
157
	Request *ServiceProviderRequest `json:"sprequest"`
Sietse Ringers's avatar
Sietse Ringers committed
158 159 160 161 162
}

// SignatureRequestorJwt is a requestor JWT for a signing session.
type SignatureRequestorJwt struct {
	ServerJwt
163
	Request *SignatureRequestorRequest `json:"absrequest"`
Sietse Ringers's avatar
Sietse Ringers committed
164 165 166 167 168
}

// IdentityProviderJwt is a requestor JWT for issuance session.
type IdentityProviderJwt struct {
	ServerJwt
169 170 171
	Request *IdentityProviderRequest `json:"iprequest"`
}

172 173 174 175 176
type RevocationJwt struct {
	ServerJwt
	Request *RevocationRequest `json:"revrequest"`
}

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
// A RequestorJwt contains an IRMA session object.
type RequestorJwt interface {
	Action() Action
	RequestorRequest() RequestorRequest
	SessionRequest() SessionRequest
	Requestor() string
	Valid() error
	Sign(jwt.SigningMethod, interface{}) (string, error)
}

// A DisclosureChoice contains the attributes chosen to be disclosed.
type DisclosureChoice struct {
	Attributes [][]*AttributeIdentifier
}

// An AttributeRequest asks for an instance of an attribute type, possibly requiring it to have
// a specified value, in a session request.
type AttributeRequest struct {
195 196 197
	Type    AttributeTypeIdentifier `json:"type"`
	Value   *string                 `json:"value,omitempty"`
	NotNull bool                    `json:"notNull,omitempty"`
198 199
}

200 201 202
type RevocationRequest struct {
	LDContext      string                   `json:"@context,omitempty"`
	CredentialType CredentialTypeIdentifier `json:"type"`
203
	Key            string                   `json:"revocationKey,omitempty"`
204 205 206 207 208 209 210 211 212
}

func (r *RevocationRequest) Validate() error {
	if r.LDContext == LDContextRevocationRequest {
		return errors.New("not a revocation request")
	}
	return nil
}

213 214 215 216 217
var (
	bigZero = big.NewInt(0)
	bigOne  = big.NewInt(1)
)

218 219 220 221
func (b *BaseRequest) Legacy() bool {
	return b.legacy
}

222 223 224
func (b *BaseRequest) GetContext() *big.Int {
	if b.Context == nil {
		return bigOne
225
	}
226
	return b.Context
227 228
}

229
func (b *BaseRequest) GetNonce(*atum.Timestamp) *big.Int {
230 231
	if b.Nonce == nil {
		return bigZero
232
	}
233
	return b.Nonce
234 235
}

Sietse Ringers's avatar
Sietse Ringers committed
236 237
// RequestsRevocation indicates whether or not the requestor requires a nonrevocation proof for
// the given credential type; that is, whether or not it included revocation update messages.
238
func (b *BaseRequest) RequestsRevocation(id CredentialTypeIdentifier) bool {
239
	return len(b.RevocationUpdates) > 0 && len(b.RevocationUpdates[id]) > 0
240 241
}

242 243 244 245 246 247 248 249 250 251 252 253
func (b *BaseRequest) RevocationConsistent() error {
	if len(b.Revocation) != len(b.RevocationUpdates) {
		return errors.New("revocation and revocationUpdates do not have the same length")
	}
	for _, typ := range b.Revocation {
		if _, present := b.RevocationUpdates[typ]; !present {
			return errors.Errorf("type %s not present in revocationUpdates", typ)
		}
	}
	return nil
}

254 255 256
// CredentialTypes returns an array of all credential types occuring in this conjunction.
func (c AttributeCon) CredentialTypes() []CredentialTypeIdentifier {
	var result []CredentialTypeIdentifier
257

258
	for _, attr := range c {
259 260 261 262
		typ := attr.Type.CredentialTypeIdentifier()
		if len(result) == 0 || result[len(result)-1] != typ {
			result = append(result, typ)
		}
263
	}
264

265
	return result
266 267
}

268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
func (c AttributeCon) Validate() error {
	// Unlike AttributeDisCon, we don't have to check here that the current instance is of length 0,
	// as that is actually a valid conjunction: one that specifies that the containing disjunction
	// is optional.

	credtypes := map[CredentialTypeIdentifier]struct{}{}
	var last CredentialTypeIdentifier
	for _, attr := range c {
		typ := attr.Type.CredentialTypeIdentifier()
		if _, contains := credtypes[typ]; contains && last != typ {
			return errors.New("Within inner conjunctions, attributes from the same credential type must be adjacent")
		}
		last = typ
		credtypes[typ] = struct{}{}
	}
	return nil
}

286 287
// AttributeRequest synonym with default JSON (un)marshaler
type jsonAttributeRequest AttributeRequest
288

289 290
func (ar *AttributeRequest) UnmarshalJSON(bts []byte) error {
	var s AttributeTypeIdentifier
291

292 293 294
	// first try to parse as JSON string into s
	if err := json.Unmarshal(bts, &s); err == nil {
		*ar = AttributeRequest{Type: s}
295 296 297
		return nil
	}

298 299
	return json.Unmarshal(bts, (*jsonAttributeRequest)(ar))
}
300

301
func (ar *AttributeRequest) MarshalJSON() ([]byte, error) {
302
	if !ar.NotNull && ar.Value == nil {
303
		return json.Marshal(ar.Type)
304
	}
305
	return json.Marshal((*jsonAttributeRequest)(ar))
306 307
}

308
// Satisfy indicates whether the given attribute type and value satisfies this AttributeRequest.
309
func (ar *AttributeRequest) Satisfy(attr AttributeTypeIdentifier, val *string) bool {
310
	return ar.Type == attr &&
311
		(!ar.NotNull || val != nil) &&
312
		(ar.Value == nil || (val != nil && *ar.Value == *val))
Sietse Ringers's avatar
Sietse Ringers committed
313 314
}

315 316
// Satisfy returns if each of the attributes specified by proofs and indices satisfies each of
// the contained AttributeRequests's. If so it also returns a list of the disclosed attribute values.
317
func (c AttributeCon) Satisfy(proofs gabi.ProofList, indices []*DisclosedAttributeIndex, revocation map[int]*time.Time, conf *Configuration) (bool, []*DisclosedAttribute, error) {
318
	if len(indices) < len(c) {
319
		return false, nil, nil
320 321
	}
	attrs := make([]*DisclosedAttribute, 0, len(c))
322 323 324
	if len(c) == 0 {
		return true, attrs, nil
	}
325 326 327

	for j := range c {
		index := indices[j]
328
		attr, val, err := extractAttribute(proofs, index, revocation[index.CredentialIndex], conf)
329
		if err != nil {
330
			return false, nil, err
331 332
		}
		if !c[j].Satisfy(attr.Identifier, val) {
333
			return false, nil, nil
334 335 336
		}
		attrs = append(attrs, attr)
	}
337
	return true, attrs, nil
338 339
}

340 341 342 343 344 345 346 347 348 349 350 351 352
func (dc AttributeDisCon) Validate() error {
	if len(dc) == 0 {
		return errors.New("Empty disjunction")
	}
	var err error
	for _, con := range dc {
		if err = con.Validate(); err != nil {
			return err
		}
	}
	return nil
}

353 354
// Satisfy returns true if the attributes specified by proofs and indices satisfies any one of the
// contained AttributeCon's. If so it also returns a list of the disclosed attribute values.
355
func (dc AttributeDisCon) Satisfy(proofs gabi.ProofList, indices []*DisclosedAttributeIndex, revocation map[int]*time.Time, conf *Configuration) (bool, []*DisclosedAttribute, error) {
356
	for _, con := range dc {
357
		satisfied, attrs, err := con.Satisfy(proofs, indices, revocation, conf)
358 359
		if satisfied || err != nil {
			return true, attrs, err
360 361
		}
	}
362
	return false, nil, nil
363 364
}

365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
func (cdc AttributeConDisCon) Validate(conf *Configuration) error {
	for _, discon := range cdc {
		for _, con := range discon {
			var nonsingleton *CredentialTypeIdentifier
			for _, attr := range con {
				typ := attr.Type.CredentialTypeIdentifier()
				if !conf.CredentialTypes[typ].IsSingleton {
					if nonsingleton != nil && *nonsingleton != typ {
						return errors.New("Multiple non-singletons within one inner conjunction are not allowed")
					} else {
						nonsingleton = &typ
					}
				}
			}
		}
	}
	return nil
}

384 385
// Satisfy returns true if each of the contained AttributeDisCon is satisfied by the specified disclosure.
// If so it also returns the disclosed attributes.
386
func (cdc AttributeConDisCon) Satisfy(disclosure *Disclosure, revocation map[int]*time.Time, conf *Configuration) (bool, [][]*DisclosedAttribute, error) {
387 388 389 390 391 392 393
	if len(disclosure.Indices) < len(cdc) {
		return false, nil, nil
	}
	list := make([][]*DisclosedAttribute, len(cdc))
	complete := true

	for i, discon := range cdc {
394
		satisfied, attrs, err := discon.Satisfy(disclosure.Proofs, disclosure.Indices[i], revocation, conf)
395 396 397
		if err != nil {
			return false, nil, err
		}
398
		if satisfied {
399 400 401 402 403 404 405 406
			list[i] = attrs
		} else {
			complete = false
			list[i] = nil
		}
	}

	return complete, list, nil
407 408
}

409 410 411 412 413 414 415 416 417 418 419 420
func (cdc AttributeConDisCon) Iterate(f func(attr *AttributeRequest) error) error {
	var err error
	for _, discon := range cdc {
		for _, con := range discon {
			for _, attr := range con {
				if err = f(&attr); err != nil {
					return err
				}
			}
		}
	}
	return nil
421 422
}

423 424 425 426 427 428 429
func (dr *DisclosureRequest) AddSingle(attr AttributeTypeIdentifier, value *string, label TranslatedString) {
	dr.Disclose = append(dr.Disclose, AttributeDisCon{AttributeCon{{Type: attr, Value: value}}})
	dr.Labels[len(dr.Disclose)-1] = label
}

func NewDisclosureRequest(attrs ...AttributeTypeIdentifier) *DisclosureRequest {
	request := &DisclosureRequest{
430
		BaseRequest: BaseRequest{LDContext: LDContextDisclosureRequest},
431 432 433 434 435 436 437 438 439 440
		Labels:      map[int]TranslatedString{},
	}
	for _, attr := range attrs {
		request.AddSingle(attr, nil, nil)
	}
	return request
}

func NewSignatureRequest(message string, attrs ...AttributeTypeIdentifier) *SignatureRequest {
	dr := NewDisclosureRequest(attrs...)
441
	dr.LDContext = LDContextSignatureRequest
442
	return &SignatureRequest{
443
		DisclosureRequest: *dr,
444 445 446 447 448 449
		Message:           message,
	}
}

func NewIssuanceRequest(creds []*CredentialRequest, attrs ...AttributeTypeIdentifier) *IssuanceRequest {
	dr := NewDisclosureRequest(attrs...)
450
	dr.LDContext = LDContextIssuanceRequest
451
	return &IssuanceRequest{
452
		DisclosureRequest: *dr,
453 454 455 456 457 458 459 460
		Credentials:       creds,
	}
}

func (dr *DisclosureRequest) Disclosure() *DisclosureRequest {
	return dr
}

461 462 463 464 465
func (dr *DisclosureRequest) identifiers() *IrmaIdentifierSet {
	ids := &IrmaIdentifierSet{
		SchemeManagers:  map[SchemeManagerIdentifier]struct{}{},
		Issuers:         map[IssuerIdentifier]struct{}{},
		CredentialTypes: map[CredentialTypeIdentifier]struct{}{},
466
		PublicKeys:      map[IssuerIdentifier][]uint{},
Leon's avatar
Leon committed
467
		AttributeTypes:  map[AttributeTypeIdentifier]struct{}{},
468 469 470 471 472 473 474
	}

	_ = dr.Disclose.Iterate(func(a *AttributeRequest) error {
		attr := a.Type
		ids.SchemeManagers[attr.CredentialTypeIdentifier().IssuerIdentifier().SchemeManagerIdentifier()] = struct{}{}
		ids.Issuers[attr.CredentialTypeIdentifier().IssuerIdentifier()] = struct{}{}
		ids.CredentialTypes[attr.CredentialTypeIdentifier()] = struct{}{}
Leon's avatar
Leon committed
475
		ids.AttributeTypes[attr] = struct{}{}
476 477 478 479 480 481
		return nil
	})

	return ids
}

482
func (dr *DisclosureRequest) Identifiers() *IrmaIdentifierSet {
483
	if dr.ids == nil {
484
		dr.ids = dr.identifiers()
485
	}
486
	return dr.ids
487 488 489 490 491 492 493 494 495
}

func (dr *DisclosureRequest) Base() *BaseRequest {
	return &dr.BaseRequest
}

func (dr *DisclosureRequest) Action() Action { return ActionDisclosing }

func (dr *DisclosureRequest) Validate() error {
496
	if dr.LDContext != LDContextDisclosureRequest {
497 498 499 500 501
		return errors.New("Not a disclosure request")
	}
	if len(dr.Disclose) == 0 {
		return errors.New("Disclosure request had no attributes")
	}
502
	var err error
503
	for _, discon := range dr.Disclose {
504 505
		if err = discon.Validate(); err != nil {
			return err
506 507
		}
	}
508 509
	return nil
}
Sietse Ringers's avatar
Sietse Ringers committed
510

511 512
func (cr *CredentialRequest) Info(conf *Configuration, metadataVersion byte) (*CredentialInfo, error) {
	list, err := cr.AttributeList(conf, metadataVersion)
513 514 515
	if err != nil {
		return nil, err
	}
516
	return NewCredentialInfo(list.Ints, conf), nil
517 518
}

519 520 521 522
// Validate checks that this credential request is consistent with the specified Configuration:
// the credential type is known, all required attributes are present and no unknown attributes
// are given.
func (cr *CredentialRequest) Validate(conf *Configuration) error {
523
	credtype := conf.CredentialTypes[cr.CredentialTypeID]
Sietse Ringers's avatar
Sietse Ringers committed
524
	if credtype == nil {
525
		return errors.New("Credential request of unknown credential type")
Sietse Ringers's avatar
Sietse Ringers committed
526
	}
527 528 529 530 531

	// Check that there are no attributes in the credential request that aren't
	// in the credential descriptor.
	for crName := range cr.Attributes {
		found := false
532
		for _, ad := range credtype.AttributeTypes {
533 534 535 536 537 538
			if ad.ID == crName {
				found = true
				break
			}
		}
		if !found {
539
			return errors.New("Credential request contains unknown attribute")
540
		}
Sietse Ringers's avatar
Sietse Ringers committed
541 542
	}

543
	for _, attrtype := range credtype.AttributeTypes {
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
		if _, present := cr.Attributes[attrtype.ID]; !present && attrtype.Optional != "true" {
			return errors.New("Required attribute not present in credential request")
		}
	}

	return nil
}

// AttributeList returns the list of attributes from this credential request.
func (cr *CredentialRequest) AttributeList(conf *Configuration, metadataVersion byte) (*AttributeList, error) {
	if err := cr.Validate(conf); err != nil {
		return nil, err
	}

	// Compute metadata attribute
	meta := NewMetadataAttribute(metadataVersion)
	meta.setKeyCounter(cr.KeyCounter)
	meta.setCredentialTypeIdentifier(cr.CredentialTypeID.String())
	meta.setSigningDate()
	if err := meta.setExpiryDate(cr.Validity); err != nil {
		return nil, err
	}

	// Compute other attributes
568
	credtype := conf.CredentialTypes[cr.CredentialTypeID]
569
	attrs := make([]*big.Int, len(credtype.AttributeTypes)+1)
Sietse Ringers's avatar
Sietse Ringers committed
570
	attrs[0] = meta.Int
571
	for i, attrtype := range credtype.AttributeTypes {
572
		attrs[i+1] = new(big.Int)
Sietse Ringers's avatar
Sietse Ringers committed
573
		if str, present := cr.Attributes[attrtype.ID]; present {
574
			// Set attribute to str << 1 + 1
575
			attrs[i+1].SetBytes([]byte(str))
576 577 578 579
			if meta.Version() >= 0x03 {
				attrs[i+1].Lsh(attrs[i+1], 1)             // attr <<= 1
				attrs[i+1].Add(attrs[i+1], big.NewInt(1)) // attr += 1
			}
Sietse Ringers's avatar
Sietse Ringers committed
580 581 582
		}
	}

583
	return NewAttributeListFromInts(attrs, conf), nil
Sietse Ringers's avatar
Sietse Ringers committed
584 585
}

Sietse Ringers's avatar
Sietse Ringers committed
586
func (ir *IssuanceRequest) Identifiers() *IrmaIdentifierSet {
587 588
	if ir.ids == nil {
		ir.ids = &IrmaIdentifierSet{
589 590 591
			SchemeManagers:  map[SchemeManagerIdentifier]struct{}{},
			Issuers:         map[IssuerIdentifier]struct{}{},
			CredentialTypes: map[CredentialTypeIdentifier]struct{}{},
Leon's avatar
Leon committed
592
			AttributeTypes:  map[AttributeTypeIdentifier]struct{}{},
593
			PublicKeys:      map[IssuerIdentifier][]uint{},
Sietse Ringers's avatar
Sietse Ringers committed
594 595
		}

Sietse Ringers's avatar
Sietse Ringers committed
596
		for _, credreq := range ir.Credentials {
Sietse Ringers's avatar
Sietse Ringers committed
597
			issuer := credreq.CredentialTypeID.IssuerIdentifier()
598 599
			ir.ids.SchemeManagers[issuer.SchemeManagerIdentifier()] = struct{}{}
			ir.ids.Issuers[issuer] = struct{}{}
Leon's avatar
Leon committed
600 601 602 603 604
			credID := credreq.CredentialTypeID
			ir.ids.CredentialTypes[credID] = struct{}{}
			for attr, _ := range credreq.Attributes { // this is kind of ugly
				ir.ids.AttributeTypes[NewAttributeTypeIdentifier(credID.String()+"."+attr)] = struct{}{}
			}
605
			if ir.ids.PublicKeys[issuer] == nil {
606
				ir.ids.PublicKeys[issuer] = []uint{}
607
			}
608
			ir.ids.PublicKeys[issuer] = append(ir.ids.PublicKeys[issuer], credreq.KeyCounter)
609 610
		}

611
		ir.ids.join(ir.DisclosureRequest.identifiers())
Sietse Ringers's avatar
Sietse Ringers committed
612
	}
613
	return ir.ids
Sietse Ringers's avatar
Sietse Ringers committed
614 615
}

Tomas's avatar
Tomas committed
616 617 618 619 620 621 622 623 624 625 626 627 628
func (ir *IssuanceRequest) GetCredentialInfoList(conf *Configuration, version *ProtocolVersion) (CredentialInfoList, error) {
	if ir.CredentialInfoList == nil {
		for _, credreq := range ir.Credentials {
			info, err := credreq.Info(conf, GetMetadataVersion(version))
			if err != nil {
				return nil, err
			}
			ir.CredentialInfoList = append(ir.CredentialInfoList, info)
		}
	}
	return ir.CredentialInfoList, nil
}

629 630
func (ir *IssuanceRequest) Action() Action { return ActionIssuing }

631
func (ir *IssuanceRequest) Validate() error {
632
	if ir.LDContext != LDContextIssuanceRequest {
633 634 635 636 637
		return errors.New("Not an issuance request")
	}
	if len(ir.Credentials) == 0 {
		return errors.New("Empty issuance request")
	}
638
	for _, cred := range ir.Credentials {
639
		if cred.Validity != nil && cred.Validity.Floor().Before(Timestamp(time.Now())) {
640 641 642
			return errors.New("Expired credential request")
		}
	}
643 644 645 646 647 648
	var err error
	for _, discon := range ir.Disclose {
		if err = discon.Validate(); err != nil {
			return err
		}
	}
649 650 651
	return nil
}

Sietse Ringers's avatar
Sietse Ringers committed
652 653
// GetNonce returns the nonce of this signature session
// (with the message already hashed into it).
654 655
func (sr *SignatureRequest) GetNonce(timestamp *atum.Timestamp) *big.Int {
	return ASN1ConvertSignatureNonce(sr.Message, sr.BaseRequest.GetNonce(nil), timestamp)
656 657
}

658
func (sr *SignatureRequest) SignatureFromMessage(message interface{}, timestamp *atum.Timestamp) (*SignedMessage, error) {
659
	signature, ok := message.(*Disclosure)
660 661 662 663 664

	if !ok {
		return nil, errors.Errorf("Type assertion failed")
	}

665 666 667 668
	nonce := sr.Nonce
	if nonce == nil {
		nonce = bigZero
	}
669
	return &SignedMessage{
670
		LDContext: LDContextSignedMessage,
671
		Signature: signature.Proofs,
672
		Indices:   signature.Indices,
673 674
		Nonce:     nonce,
		Context:   sr.GetContext(),
675
		Message:   sr.Message,
676
		Timestamp: timestamp,
677 678 679
	}, nil
}

680 681
func (sr *SignatureRequest) Action() Action { return ActionSigning }

682
func (sr *SignatureRequest) Validate() error {
683
	if sr.LDContext != LDContextSignatureRequest {
684 685 686 687 688
		return errors.New("Not a signature request")
	}
	if sr.Message == "" {
		return errors.New("Signature request had empty message")
	}
689 690
	if len(sr.Disclose) == 0 {
		return errors.New("Signature request had no attributes")
691
	}
692
	var err error
693
	for _, discon := range sr.Disclose {
694 695
		if err = discon.Validate(); err != nil {
			return err
696 697
		}
	}
698 699 700
	return nil
}

701 702 703 704 705
// Check if Timestamp is before other Timestamp. Used for checking expiry of attributes
func (t Timestamp) Before(u Timestamp) bool {
	return time.Time(t).Before(time.Time(u))
}

706 707 708 709
func (t Timestamp) After(u Timestamp) bool {
	return time.Time(t).After(time.Time(u))
}

710 711 712 713 714
// To check whether Timestamp is uninitialized
func (t Timestamp) IsZero() bool {
	return time.Time(t).IsZero()
}

715 716 717 718 719 720 721 722 723 724 725 726 727
func (t *Timestamp) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	return e.EncodeElement(t.String(), start)
}

func (t *Timestamp) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var ts int64
	if err := d.DecodeElement(&ts, &start); err != nil {
		return err
	}
	*t = Timestamp(time.Unix(ts, 0))
	return nil
}

728 729
// MarshalJSON marshals a timestamp.
func (t *Timestamp) MarshalJSON() ([]byte, error) {
730
	return []byte(t.String()), nil
731 732 733 734 735 736 737 738 739 740 741
}

// 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
}
Sietse Ringers's avatar
Sietse Ringers committed
742

743 744 745 746 747
// Timestamp implements Stringer.
func (t *Timestamp) String() string {
	return fmt.Sprint(time.Time(*t).Unix())
}

748 749 750 751
func (t *Timestamp) Floor() Timestamp {
	return Timestamp(time.Unix((time.Time(*t).Unix()/ExpiryFactor)*ExpiryFactor, 0))
}

752 753 754 755 756 757 758 759
func readTimestamp(path string) (*Timestamp, bool, error) {
	exists, err := fs.PathExists(path)
	if err != nil {
		return nil, false, err
	}
	if !exists {
		return nil, false, nil
	}
760 761
	bts, err := ioutil.ReadFile(path)
	if err != nil {
762
		return nil, true, errors.New("Could not read scheme manager timestamp")
763
	}
764 765
	ts, err := parseTimestamp(bts)
	return ts, true, err
766 767
}

768
func parseTimestamp(bts []byte) (*Timestamp, error) {
769 770 771 772 773 774
	// Remove final character \n if present
	if bts[len(bts)-1] == '\n' {
		bts = bts[:len(bts)-1]
	}
	// convert from byte slice to string; parse as int
	str, err := strconv.ParseInt(string(bts), 10, 64)
775
	if err != nil {
776
		return nil, err
777
	}
778 779
	ts := Timestamp(time.Unix(str, 0))
	return &ts, nil
780 781
}

Sietse Ringers's avatar
Sietse Ringers committed
782 783 784 785 786 787 788 789
// NewServiceProviderJwt returns a new ServiceProviderJwt.
func NewServiceProviderJwt(servername string, dr *DisclosureRequest) *ServiceProviderJwt {
	return &ServiceProviderJwt{
		ServerJwt: ServerJwt{
			ServerName: servername,
			IssuedAt:   Timestamp(time.Now()),
			Type:       "verification_request",
		},
790 791 792 793
		Request: &ServiceProviderRequest{
			RequestorBaseRequest: RequestorBaseRequest{ResultJwtValidity: 120},
			Request:              dr,
		},
Sietse Ringers's avatar
Sietse Ringers committed
794 795 796 797 798 799 800 801 802 803 804
	}
}

// NewSignatureRequestorJwt returns a new SignatureRequestorJwt.
func NewSignatureRequestorJwt(servername string, sr *SignatureRequest) *SignatureRequestorJwt {
	return &SignatureRequestorJwt{
		ServerJwt: ServerJwt{
			ServerName: servername,
			IssuedAt:   Timestamp(time.Now()),
			Type:       "signature_request",
		},
805 806 807 808
		Request: &SignatureRequestorRequest{
			RequestorBaseRequest: RequestorBaseRequest{ResultJwtValidity: 120},
			Request:              sr,
		},
Sietse Ringers's avatar
Sietse Ringers committed
809 810 811 812 813 814 815 816 817 818 819
	}
}

// NewIdentityProviderJwt returns a new IdentityProviderJwt.
func NewIdentityProviderJwt(servername string, ir *IssuanceRequest) *IdentityProviderJwt {
	return &IdentityProviderJwt{
		ServerJwt: ServerJwt{
			ServerName: servername,
			IssuedAt:   Timestamp(time.Now()),
			Type:       "issue_request",
		},
820 821 822 823
		Request: &IdentityProviderRequest{
			RequestorBaseRequest: RequestorBaseRequest{ResultJwtValidity: 120},
			Request:              ir,
		},
Sietse Ringers's avatar
Sietse Ringers committed
824 825 826
	}
}

827 828 829 830 831 832 833
func (jwt *ServerJwt) Requestor() string { return jwt.ServerName }

func (r *ServiceProviderRequest) Validate() error {
	if r.Request == nil {
		return errors.New("Not a ServiceProviderRequest")
	}
	return r.Request.Validate()
Sietse Ringers's avatar
Sietse Ringers committed
834 835
}

836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
func (r *SignatureRequestorRequest) Validate() error {
	if r.Request == nil {
		return errors.New("Not a SignatureRequestorRequest")
	}
	return r.Request.Validate()
}

func (r *IdentityProviderRequest) Validate() error {
	if r.Request == nil {
		return errors.New("Not a IdentityProviderRequest")
	}
	return r.Request.Validate()
}

func (r *ServiceProviderRequest) SessionRequest() SessionRequest {
	return r.Request
}

func (r *SignatureRequestorRequest) SessionRequest() SessionRequest {
	return r.Request
}

func (r *IdentityProviderRequest) SessionRequest() SessionRequest {
	return r.Request
}

func (r *ServiceProviderRequest) Base() RequestorBaseRequest {
	return r.RequestorBaseRequest
}

func (r *SignatureRequestorRequest) Base() RequestorBaseRequest {
	return r.RequestorBaseRequest
}

func (r *IdentityProviderRequest) Base() RequestorBaseRequest {
	return r.RequestorBaseRequest
}
873

874
// SessionRequest returns an IRMA session object.
875
func (claims *ServiceProviderJwt) SessionRequest() SessionRequest { return claims.Request.Request }
Sietse Ringers's avatar
Sietse Ringers committed
876

877
// SessionRequest returns an IRMA session object.
878
func (claims *SignatureRequestorJwt) SessionRequest() SessionRequest { return claims.Request.Request }
Sietse Ringers's avatar
Sietse Ringers committed
879

880
// SessionRequest returns an IRMA session object.
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
func (claims *IdentityProviderJwt) SessionRequest() SessionRequest { return claims.Request.Request }

func (claims *ServiceProviderJwt) Sign(method jwt.SigningMethod, key interface{}) (string, error) {
	return jwt.NewWithClaims(method, claims).SignedString(key)
}

func (claims *SignatureRequestorJwt) Sign(method jwt.SigningMethod, key interface{}) (string, error) {
	return jwt.NewWithClaims(method, claims).SignedString(key)
}

func (claims *IdentityProviderJwt) Sign(method jwt.SigningMethod, key interface{}) (string, error) {
	return jwt.NewWithClaims(method, claims).SignedString(key)
}

func (claims *ServiceProviderJwt) RequestorRequest() RequestorRequest { return claims.Request }

func (claims *SignatureRequestorJwt) RequestorRequest() RequestorRequest { return claims.Request }

func (claims *IdentityProviderJwt) RequestorRequest() RequestorRequest { return claims.Request }

func (claims *ServiceProviderJwt) Valid() error {
	if claims.Type != "verification_request" {
903 904 905

		return errors.New("Verification jwt has invalid subject")
	}
906
	if time.Time(claims.IssuedAt).After(time.Now()) {
907 908 909 910 911
		return errors.New("Verification jwt not yet valid")
	}
	return nil
}

912 913
func (claims *SignatureRequestorJwt) Valid() error {
	if claims.Type != "signature_request" {
914 915
		return errors.New("Signature jwt has invalid subject")
	}
916
	if time.Time(claims.IssuedAt).After(time.Now()) {
917 918 919 920 921
		return errors.New("Signature jwt not yet valid")
	}
	return nil
}

922 923
func (claims *IdentityProviderJwt) Valid() error {
	if claims.Type != "issue_request" {
924 925
		return errors.New("Issuance jwt has invalid subject")
	}
926
	if time.Time(claims.IssuedAt).After(time.Now()) {
927 928 929 930 931
		return errors.New("Issuance jwt not yet valid")
	}
	return nil
}

932 933 934 935 936 937 938
func (claims *RevocationJwt) Valid() error {
	if time.Time(claims.IssuedAt).After(time.Now()) {
		return errors.New("Signature jwt not yet valid")
	}
	return nil
}

939 940 941 942
func (claims *RevocationJwt) Sign(method jwt.SigningMethod, key interface{}) (string, error) {
	return jwt.NewWithClaims(method, claims).SignedString(key)
}