Commit 75c9bfb3 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Create disclosure and signing proofs

parent e42904e3
......@@ -225,6 +225,12 @@ func shortToByte(x int) []byte {
return bytes
}
// A DisclosureChoice contains the attributes chosen to be disclosed.
type DisclosureChoice struct {
Session SessionRequest
Attributes []*AttributeIdentifier
}
// An AttributeDisjunction encapsulates a list of possible attributes, one
// of which should be disclosed.
type AttributeDisjunction struct {
......
......@@ -3,6 +3,8 @@ package irmago
import (
"encoding/xml"
"errors"
"github.com/mhe/gabi"
)
......@@ -66,6 +68,18 @@ type AttributeDescription struct {
Description TranslatedString
}
func (ct CredentialType) IndexOf(ai AttributeTypeIdentifier) (int, error) {
if ai.CredentialTypeIdentifier() != ct.Identifier() {
return -1, errors.New("Wrong credential type")
}
for i, description := range ct.Attributes {
if description.ID == ai.Name() {
return i, nil
}
}
return -1, errors.New("Attribute identifier not found")
}
// TranslatedString represents an XML tag containing a string translated to multiple languages.
// For example: <Foo id="bla"><Translation lang="en">Hello world</Translation><Translation lang="nl">Hallo wereld</Translation></Foo>
// type TranslatedString struct {
......
......@@ -88,3 +88,7 @@ func (id AttributeTypeIdentifier) CredentialTypeIdentifier() CredentialTypeIdent
func (id AttributeTypeIdentifier) IsCredential() bool {
return strings.Count(id.String(), ".") == 2
}
func (ai *AttributeIdentifier) CredentialIdentifier() CredentialIdentifier {
return CredentialIdentifier{Type: ai.Type.CredentialTypeIdentifier(), Index: ai.Index, Count: ai.Count}
}
......@@ -78,6 +78,10 @@ func (cm *CredentialManager) Attributes(id CredentialTypeIdentifier, counter int
return list[counter]
}
func (cm *CredentialManager) CredentialByID(id CredentialIdentifier) (cred *Credential, err error) {
return cm.Credential(id.Type, id.Count)
}
// Credential returns the requested credential, or nil if we do not have it.
func (cm *CredentialManager) Credential(id CredentialTypeIdentifier, counter int) (cred *Credential, err error) {
// If the requested credential is not in credential map, we check if its attributes were
......@@ -243,3 +247,58 @@ func (cm *CredentialManager) CheckSatisfiability(disjunctions DisjunctionListCon
return missing
}
func (cm *CredentialManager) groupCredentials(choice DisclosureChoice) (map[CredentialIdentifier][]int, error) {
grouped := make(map[CredentialIdentifier][]int)
for _, attribute := range choice.Attributes {
identifier := attribute.Type
ici := attribute.CredentialIdentifier()
// If this is the first attribute of its credential type that we encounter
// in the disclosure choice, then there is no slice yet at grouped[ici]
var indices []int
if _, present := grouped[ici]; !present {
indices = []int{1} // Always include metadata
grouped[ici] = indices
}
indices = grouped[ici]
if identifier.IsCredential() {
continue // In this case we only disclose the metadata attribute, which is already handled
}
index, err := MetaStore.Credentials[identifier.CredentialTypeIdentifier()].IndexOf(identifier)
if err != nil {
return nil, err
}
// These indices will be used in the []*big.Int at gabi.Credential.Attributes,
// which doesn't know about the secret key and metadata attribute, so +2
indices = append(indices, index+2)
}
return grouped, nil
}
type SessionRequest interface {
GetNonce() *big.Int
GetContext() *big.Int
}
func (cm *CredentialManager) Proofs(choice DisclosureChoice, message *string) (gabi.ProofList, error) {
todisclose, err := cm.groupCredentials(choice)
if err != nil {
return nil, err
}
builders := []gabi.ProofBuilder{}
for id, list := range todisclose {
cred, err := cm.CredentialByID(id)
if err != nil {
return nil, err
}
builders = append(builders, cred.Credential.CreateDisclosureProofBuilder(list))
}
return gabi.BuildProofList(choice.Session.GetContext(), choice.Session.GetNonce(), builders), nil
}
......@@ -65,11 +65,6 @@ type SessionInfo struct {
Keys map[irmago.IssuerIdentifier]int `json:"keys"`
}
// A DisclosureChoice contains the attributes chosen to be disclosed.
type DisclosureChoice struct {
Attributes []*irmago.AttributeIdentifier
}
// MarshalJSON marshals a timestamp.
func (t *Timestamp) MarshalJSON() ([]byte, error) {
ts := time.Time(*t).Unix()
......
package protocol
import (
"encoding/asn1"
"math/big"
"crypto/sha256"
"log"
"github.com/credentials/irmago"
)
......@@ -62,6 +67,32 @@ type IdentityProviderRequest struct {
} `json:"iprequest"`
}
func (dr *DisclosureRequest) GetContext() *big.Int {
return dr.Context
}
func (dr *DisclosureRequest) GetNonce() *big.Int {
return dr.Nonce
}
func (sr *SignatureRequest) GetContext() *big.Int {
return sr.Context
}
func (sr *SignatureRequest) GetNonce() *big.Int {
// BigInteger messageHash = Crypto.sha256Hash(message.getBytes());
// return Crypto.sha256Hash(Crypto.asn1Encode(nonce, messageHash));
hashbytes := sha256.Sum256([]byte(sr.Message))
hashint := new(big.Int).SetBytes(hashbytes[:])
asn1bytes, err := asn1.Marshal([]*big.Int{sr.Nonce, hashint})
if err != nil {
log.Print(err) // TODO? does this happen?
}
asn1hash := sha256.Sum256(asn1bytes)
return new(big.Int).SetBytes(asn1hash[:])
}
func (spr *ServiceProviderRequest) DisjunctionList() irmago.AttributeDisjunctionList {
return spr.Request.Request.Content
}
......
......@@ -8,7 +8,7 @@ import (
"github.com/credentials/irmago"
)
type PermissionHandler func(proceed bool, choice *DisclosureChoice)
type PermissionHandler func(proceed bool, choice *irmago.DisclosureChoice)
// A Handler contains callbacks for communication to the user.
type Handler interface {
......@@ -92,12 +92,11 @@ func (session *Session) start() {
session.Handler.Failure(session.Action, ErrorInvalidJWT, "")
return
}
headerjson := jwtparts[0]
reqjson := jwtparts[1]
var header struct {
Server string `json:"iss"`
}
json.Unmarshal([]byte(headerjson), &header)
json.Unmarshal([]byte(jwtparts[0]), &header)
json.Unmarshal([]byte(jwtparts[1]), session.request)
switch session.Action {
case ActionDisclosing:
......@@ -109,7 +108,7 @@ func (session *Session) start() {
default:
panic("Invalid session type") // does not happen, session.Action has been checked earlier
}
json.Unmarshal([]byte(reqjson), session.request)
if session.Action == ActionIssuing {
// Store which public keys the server will use
for _, credreq := range session.request.(*IdentityProviderRequest).Request.Request.Credentials {
......@@ -123,7 +122,7 @@ func (session *Session) start() {
return
}
callback := PermissionHandler(func(proceed bool, choice *DisclosureChoice) {
callback := PermissionHandler(func(proceed bool, choice *irmago.DisclosureChoice) {
go session.do(proceed, choice)
})
......@@ -140,6 +139,11 @@ func (session *Session) start() {
}
}
func (session *Session) do(proceed bool, choice *DisclosureChoice) {
// TODO
func (session *Session) do(proceed bool, choice *irmago.DisclosureChoice) {
if !proceed {
session.Handler.Cancelled(session.Action)
return
}
session.Handler.StatusUpdate(session.Action, StatusCommunicating)
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment