Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

native support for token verification #418

Merged
merged 3 commits into from
May 17, 2022
Merged
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
36 changes: 20 additions & 16 deletions include/okapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ int32_t didkey_resolve(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t blake3_hash(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t blake3_keyed_hash(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t blake3_derive_key(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t sha256_hash(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t ldproofs_create_proof(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);
Expand All @@ -63,6 +79,10 @@ int32_t oberon_unblind_token(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t oberon_verify_token(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t oberon_create_proof(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);
Expand All @@ -78,19 +98,3 @@ void didcomm_string_free(char *s);
void okapi_bytebuffer_free(struct ByteBuffer v);

void okapi_string_free(char *s);

int32_t blake3_hash(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t blake3_keyed_hash(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t blake3_derive_key(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t sha256_hash(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);
1 change: 0 additions & 1 deletion native/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ fn compile_protobuf_files() {
],
&["../proto", "../proto/pbmse/v1/"],
)
.format(true)
fundthmcalculus marked this conversation as resolved.
Show resolved Hide resolved
.unwrap();

copy("okapi.examples.v1.rs", "./src/proto/okapi/okapi_examples.rs").unwrap();
Expand Down
5 changes: 5 additions & 0 deletions native/src/ffi/oberon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ pub extern "C" fn oberon_unblind_token(request: ByteBuffer, response: &mut ByteB
c_impl!(UnBlindOberonTokenRequest, Oberon, unblind, request, response, err)
}

#[no_mangle]
pub extern "C" fn oberon_verify_token(request: ByteBuffer, response: &mut ByteBuffer, err: &mut ExternError) -> i32 {
c_impl!(VerifyOberonTokenRequest, Oberon, verify_token, request, response, err)
}

#[no_mangle]
pub extern "C" fn oberon_create_proof(request: ByteBuffer, response: &mut ByteBuffer, err: &mut ExternError) -> i32 {
c_impl!(CreateOberonProofRequest, Oberon, proof, request, response, err)
Expand Down
75 changes: 49 additions & 26 deletions native/src/oberon/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::{didcomm::Error, proto::security::*};
use std::convert::TryInto;

use oberon;
use rand::prelude::*;
use std::convert::TryInto;

use crate::{didcomm::Error, proto::security::*};

impl crate::Oberon {
pub fn key<'a>(request: &CreateOberonKeyRequest) -> Result<CreateOberonKeyResponse, Error<'a>> {
Expand All @@ -24,10 +26,11 @@ impl crate::Oberon {
return Err(Error::InvalidField("must provide data"));
}

let skbytes: [u8; oberon::SecretKey::BYTES] = match request.sk.as_slice().try_into() {
Ok(skbytes) => skbytes,
Err(_) => return Err(Error::InvalidField("invalid secret key provided")),
};
let skbytes: [u8; oberon::SecretKey::BYTES] = request
.sk
.as_slice()
.try_into()
.map_err(|_| Error::InvalidField("invalid secret key provided"))?;

let sk = oberon::SecretKey::from(&skbytes);
let mut token = match oberon::Token::new(&sk, &request.data) {
Expand All @@ -51,10 +54,7 @@ impl crate::Oberon {
return Err(Error::InvalidField("must provide data"));
}

let tokenbytes: [u8; oberon::Token::BYTES] = match request.token.as_slice().try_into() {
Ok(tokenbytes) => tokenbytes,
Err(_) => return Err(Error::InvalidField("invalid token provided")),
};
let tokenbytes: [u8; oberon::Token::BYTES] = request.token.as_slice().try_into().map_err(|_| Error::InvalidField("invalid token provided"))?;

let tkn = oberon::Token::from_bytes(&tokenbytes);
if tkn.is_none().into() {
Expand All @@ -80,20 +80,18 @@ impl crate::Oberon {
return Err(Error::InvalidField("must provide data"));
}

let pkbytes: [u8; oberon::PublicKey::BYTES] = match request.pk.as_slice().try_into() {
Ok(pkbytes) => pkbytes,
Err(_) => return Err(Error::InvalidField("invalid public key provided")),
};
let pkbytes: [u8; oberon::PublicKey::BYTES] = request
.pk
.as_slice()
.try_into()
.map_err(|_| Error::InvalidField("invalid public key provided"))?;

let pk = oberon::PublicKey::from_bytes(&pkbytes);
if pk.is_none().into() {
return Err(Error::InvalidField("invalid public key provided"));
}

let proofbytes: [u8; oberon::Proof::BYTES] = match request.proof.as_slice().try_into() {
Ok(proofbytes) => proofbytes,
Err(_) => return Err(Error::InvalidField("invalid proof provided")),
};
let proofbytes: [u8; oberon::Proof::BYTES] = request.proof.as_slice().try_into().map_err(|_| Error::InvalidField("invalid proof provided"))?;

let proof = oberon::Proof::from_bytes(&proofbytes);
if proof.is_none().into() {
Expand All @@ -106,10 +104,7 @@ impl crate::Oberon {
}

pub fn blind<'a>(request: &BlindOberonTokenRequest) -> Result<BlindOberonTokenResponse, Error<'a>> {
let tokenbytes: [u8; oberon::Token::BYTES] = match request.token.as_slice().try_into() {
Ok(tokenbytes) => tokenbytes,
Err(_) => return Err(Error::InvalidField("invalid token provided")),
};
let tokenbytes: [u8; oberon::Token::BYTES] = request.token.as_slice().try_into().map_err(|_| Error::InvalidField("invalid token provided"))?;

let tkn = oberon::Token::from_bytes(&tokenbytes);
if tkn.is_none().into() {
Expand All @@ -130,10 +125,7 @@ impl crate::Oberon {
}

pub fn unblind<'a>(request: &UnBlindOberonTokenRequest) -> Result<BlindOberonTokenResponse, Error<'a>> {
let tokenbytes: [u8; oberon::Token::BYTES] = match request.token.as_slice().try_into() {
Ok(tokenbytes) => tokenbytes,
Err(_) => return Err(Error::InvalidField("invalid token provided")),
};
let tokenbytes: [u8; oberon::Token::BYTES] = request.token.as_slice().try_into().map_err(|_| Error::InvalidField("invalid token provided"))?;

let tkn = oberon::Token::from_bytes(&tokenbytes);
if tkn.is_none().into() {
Expand All @@ -152,4 +144,35 @@ impl crate::Oberon {
token: tkn.to_bytes().to_vec(),
})
}

pub fn verify_token<'a>(request: &VerifyOberonTokenRequest) -> Result<VerifyOberonTokenResponse, Error<'a>> {
if request.data.len() == 0 {
return Err(Error::InvalidField("must provide data"));
}

let pkbytes: [u8; oberon::PublicKey::BYTES] = request
.pk
.as_slice()
.try_into()
.map_err(|_| Error::InvalidField("invalid public key provided"))?;

let pk = oberon::PublicKey::from_bytes(&pkbytes);
if pk.is_none().into() {
return Err(Error::InvalidField("invalid public key provided"));
}

let tokenbytes: [u8; oberon::Token::BYTES] = request.token.as_slice().try_into().map_err(|_| Error::InvalidField("invalid token provided"))?;

let tkn = oberon::Token::from_bytes(&tokenbytes);
if tkn.is_none().into() {
return Err(Error::InvalidField("invalid token provided"));
}
let tkn = tkn.unwrap();
let pk = pk.unwrap();

let verify_result = tkn.verify(pk, &request.data);
let is_valid = bool::from(verify_result);

Ok(VerifyOberonTokenResponse { valid: is_valid })
}
}
20 changes: 20 additions & 0 deletions native/src/proto/okapi/okapi_security.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,23 @@ pub struct UnBlindOberonTokenResponse {
#[prost(bytes = "vec", tag = "1")]
pub token: ::prost::alloc::vec::Vec<u8>,
}
/// Verify that an oberon token comes from the desired issuer
#[derive(::serde::Serialize, ::serde::Deserialize, Clone, PartialEq, ::prost::Message)]
pub struct VerifyOberonTokenRequest {
/// raw token bytes
#[prost(bytes = "vec", tag = "1")]
pub token: ::prost::alloc::vec::Vec<u8>,
/// token is valid to this public key?
#[prost(bytes = "vec", tag = "2")]
pub pk: ::prost::alloc::vec::Vec<u8>,
/// public part of oberon protocol - can be any data
#[prost(bytes = "vec", tag = "3")]
pub data: ::prost::alloc::vec::Vec<u8>,
}
/// Contains the verification result for the oberon token
#[derive(::serde::Serialize, ::serde::Deserialize, Clone, PartialEq, ::prost::Message)]
pub struct VerifyOberonTokenResponse {
/// token is valid to the public key
#[prost(bool, tag = "1")]
pub valid: bool,
}
2 changes: 0 additions & 2 deletions native/src/proto/pbmse.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
mod pbmse;

/// JWS
/// Protocol buffer message signing and encryption
#[derive(::serde::Serialize, ::serde::Deserialize, Clone, PartialEq, ::prost::Message)]
Expand Down
32 changes: 32 additions & 0 deletions native/src/tests/oberon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,38 @@ fn test_unblind_token() {
);
}

#[test]
fn test_verify_token() {
let data = vec![4, 1, 1, 3];
let req = CreateOberonKeyRequest { seed: vec![1, 2, 3] };
let key_resp = crate::Oberon::key(&req).unwrap();
let token = crate::Oberon::token(&CreateOberonTokenRequest {
sk: key_resp.sk,
data: data.clone(),
blinding: vec![],
})
.unwrap();

// Verify with proper public key
let key_verify_good = crate::Oberon::verify_token(&VerifyOberonTokenRequest {
token: token.token.clone(),
pk: key_resp.pk.clone(),
data: data.clone(),
})
.unwrap();
assert_eq!(key_verify_good.valid, true);

// Verify with improper public key
let wrong_key = crate::Oberon::key(&CreateOberonKeyRequest { seed: vec![0, 1, 2] }).unwrap();
let key_verify_bad = crate::Oberon::verify_token(&VerifyOberonTokenRequest {
token: token.token.clone(),
pk: wrong_key.pk.clone(),
data: data.clone(),
})
.unwrap();
assert_eq!(key_verify_bad.valid, false);
}

#[test]
fn test_create_key() {
let req = CreateOberonKeyRequest { seed: vec![] };
Expand Down
12 changes: 12 additions & 0 deletions proto/okapi/security/v1/security.proto
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,15 @@ message UnBlindOberonTokenRequest {
message UnBlindOberonTokenResponse {
bytes token = 1; // raw unblinded token bytes
}

// Verify that an oberon token comes from the desired issuer
message VerifyOberonTokenRequest {
bytes token = 1; // raw token bytes
bytes pk = 2; // token is valid to this public key?
bytes data = 3; // public part of oberon protocol - can be any data
}

// Contains the verification result for the oberon token
message VerifyOberonTokenResponse {
bool valid = 1; // token is valid to the public key
}
1 change: 0 additions & 1 deletion python/tests/test_oberon.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import base64
import unittest

from trinsicokapi import oberon
Expand Down