Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 21 additions & 18 deletions pg-pkg/src/handlers/signing_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use irma::SessionStatus;
use pg_core::api::{SigningKeyRequest, SigningKeyResponse};
use pg_core::artifacts::{SigningKey, SigningKeyExt};
use pg_core::ibs::gg::{keygen, SecretKey};
use pg_core::identity::{Attribute, Policy};
use pg_core::identity::Policy;

use crate::middleware::auth::AuthResult;
use crate::util::current_time_u64;
Expand Down Expand Up @@ -71,27 +71,30 @@ pub async fn signing_key(
policy,
};

let priv_sign_key = body.priv_sign_id.as_ref().map(|priv_sign_id| {
let priv_con = con
let priv_sign_key = if let Some(priv_sign_id) = body.priv_sign_id.as_ref() {
let priv_con: Vec<_> = con
.clone()
.into_iter()
.filter(|a| priv_sign_id.contains(&Attribute::new(&a.atype, None)))
.filter(|a| priv_sign_id.iter().any(|req| req.atype == a.atype))
.collect();
let policy = Policy {
timestamp: iat,
con: priv_con,
};

let id = policy.derive_ibs().map_err(|_e| crate::Error::Unexpected)?;
let key = keygen(sk, &id, &mut rng);

Ok(SigningKeyExt {
key: SigningKey(key),
policy,
})
});

let priv_sign_key = priv_sign_key.map_or(Ok(None), |r| r.map(Some))?;
if priv_con.is_empty() {
None
} else {
let policy = Policy {
timestamp: iat,
con: priv_con,
};
let id = policy.derive_ibs().map_err(|_e| crate::Error::Unexpected)?;
let key = keygen(sk, &id, &mut rng);
Some(SigningKeyExt {
key: SigningKey(key),
policy,
})
}
} else {
None
};

Ok(HttpResponse::Ok().json(SigningKeyResponse {
status,
Expand Down
126 changes: 122 additions & 4 deletions pg-pkg/src/handlers/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,130 @@ async fn create_irma_session(
dr: IrmaRequest,
validity: Option<u64>,
) -> Result<HttpResponse, Error> {
let validity = match validity {
Some(v) if v > MAX_VALIDITY => return Err(Error::ValidityError),
Some(v) => v,
None => DEFAULT_VALIDITY,
let irma_url = url.get_ref().0.clone();
let irma_token = irma_token.get_ref().0.clone();
let kr = value.into_inner();

const EMAIL_ATTR: &str = "pbdf.sidn-pbdf.email.email";

// Determine whether this is a decryption request (kr.con contains non-email attributes
// from the encrypted policy) or a signing request (email-only or empty con).
let has_policy_attrs = kr.con.iter().any(|a| a.atype != EMAIL_ATTR);

let dr = if has_policy_attrs {
// Decryption flow: make every attribute from the policy mandatory so the
// recipient must disclose the exact combination that was used for encryption.
let discons: Vec<Vec<Vec<AttributeRequest>>> = kr
.con
.iter()
.map(|attr| {
vec![vec![AttributeRequest::Compound {
attr_type: attr.atype.clone(),
value: None,
not_null: true,
}]]
})
.collect();

DisclosureRequestBuilder::new().add_discons(discons).build()
} else {
// Signing flow: email is required, the rest are optional so the sender can
// choose what extra attributes to include in their signing identity.
let mandatory: Vec<Vec<Vec<AttributeRequest>>> =
vec![vec![vec![AttributeRequest::Compound {
attr_type: EMAIL_ATTR.to_string(),
value: None,
not_null: true,
}]]];

// Optional disjunctions: each starts with an empty conjunction so the user may skip it.
let optional: Vec<Vec<Vec<AttributeRequest>>> = vec![
// Phone number
vec![
vec![],
vec![AttributeRequest::Compound {
attr_type: "pbdf.sidn-pbdf.mobilenumber.mobilenumber".to_string(),
value: None,
not_null: true,
}],
],
// Full name: driving licence, ID card, or passport
vec![
vec![],
vec![
AttributeRequest::Compound {
attr_type: "pbdf.pbdf.drivinglicence.firstName".to_string(),
value: None,
not_null: true,
},
AttributeRequest::Compound {
attr_type: "pbdf.pbdf.drivinglicence.lastName".to_string(),
value: None,
not_null: true,
},
],
vec![
AttributeRequest::Compound {
attr_type: "pbdf.pbdf.idcard.firstName".to_string(),
value: None,
not_null: true,
},
AttributeRequest::Compound {
attr_type: "pbdf.pbdf.idcard.lastName".to_string(),
value: None,
not_null: true,
},
],
vec![
AttributeRequest::Compound {
attr_type: "pbdf.pbdf.passport.firstName".to_string(),
value: None,
not_null: true,
},
AttributeRequest::Compound {
attr_type: "pbdf.pbdf.passport.lastName".to_string(),
value: None,
not_null: true,
},
],
],
// Date of birth: driving licence, ID card, or passport
vec![
vec![],
vec![AttributeRequest::Compound {
attr_type: "pbdf.pbdf.drivinglicence.dateOfBirth".to_string(),
value: None,
not_null: true,
}],
vec![AttributeRequest::Compound {
attr_type: "pbdf.pbdf.idcard.dateOfBirth".to_string(),
value: None,
not_null: true,
}],
vec![AttributeRequest::Compound {
attr_type: "pbdf.pbdf.passport.dateOfBirth".to_string(),
value: None,
not_null: true,
}],
],
];

DisclosureRequestBuilder::new()
.add_discons([mandatory, optional].concat())
.build()
};

log::debug!(
"disclosure request: {}",
serde_json::to_string_pretty(&dr).unwrap_or_default()
);

let validity = match kr.validity {
Some(validity) if validity > MAX_VALIDITY => Err(Error::ValidityError),
Some(validity) => Ok(validity),
None => Ok(DEFAULT_VALIDITY),
}?;

let er = ExtendedIrmaRequest {
timeout: None,
callback_url: None,
Expand Down
Loading