Skip to content

Commit c8da72d

Browse files
committed
long signature certificates
Signed-off-by: Dr Maxim Orlovsky <[email protected]>
1 parent e340d02 commit c8da72d

File tree

4 files changed

+56
-8
lines changed

4 files changed

+56
-8
lines changed

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub use ed25519::Ed25519Secret;
3535
pub use identity::{Ssi, SsiParseError, Uid};
3636
pub use public::{
3737
Algo, CertParseError, Chain, Fingerprint, InvalidPubkey, InvalidSig, SsiCert, SsiPub, SsiQuery,
38-
SsiSig, UnknownAlgo, UnknownChain,
38+
SsiSig, UnknownAlgo, UnknownChain, VerifyError,
3939
};
4040
pub use runtime::{Error, SsiRuntime, SSI_DIR};
4141
pub use secret::{SecretParseError, SsiPair, SsiSecret};

src/main.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ pub enum Command {
8181

8282
/// Sign a file or a message
8383
Sign {
84+
/// Generate signature including the full identity
85+
#[clap(long)]
86+
full: bool,
87+
8488
/// Text message to sign
8589
#[clap(short, long, conflicts_with = "file")]
8690
text: Option<String>,
@@ -177,7 +181,12 @@ fn main() {
177181
runtime.store().expect("unable to save data");
178182
}
179183

180-
Command::Sign { text, file, ssi } => {
184+
Command::Sign {
185+
full,
186+
text,
187+
file,
188+
ssi,
189+
} => {
181190
eprintln!("Signing with {ssi} ...");
182191

183192
let passwd = rpassword::prompt_password("Password for private key encryption: ")
@@ -199,15 +208,21 @@ fn main() {
199208
.expect("unknown signing identity");
200209
eprintln!("Using key {signer}");
201210
let cert = signer.sign(msg);
202-
println!("{cert}");
211+
if full {
212+
println!("{cert:#}");
213+
} else {
214+
println!("{cert}");
215+
}
203216
}
204217

205218
Command::Verify { signature } => {
206219
eprint!("Verifying signature for message digest {} ... ", signature.msg);
207-
let ssi = runtime
220+
let pk = runtime
208221
.find_identity(signature.fp)
222+
.map(|ssi| ssi.pk)
223+
.or(signature.pk)
209224
.expect("unknown signing identity");
210-
match ssi.pk.verify(signature.msg.to_byte_array(), signature.sig) {
225+
match pk.verify(signature.msg.to_byte_array(), signature.sig) {
211226
Ok(_) => eprintln!("valid"),
212227
Err(err) => eprintln!("invalid: {err}"),
213228
}

src/public.rs

+35-3
Original file line numberDiff line numberDiff line change
@@ -288,17 +288,38 @@ impl FromStr for Fingerprint {
288288
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
289289
pub struct SsiCert {
290290
pub fp: Fingerprint,
291+
pub pk: Option<SsiPub>,
291292
pub msg: Bytes32,
292293
pub sig: SsiSig,
293294
}
294295

296+
#[derive(Debug, Display, Error, From)]
297+
#[display(inner)]
298+
pub enum VerifyError {
299+
#[display("the certificate has no identity, verification impossible.")]
300+
NoIdentity,
301+
#[from]
302+
InvalidSig(InvalidSig),
303+
}
304+
305+
impl SsiCert {
306+
pub fn verify(&self) -> Result<(), VerifyError> {
307+
let Some(pk) = self.pk else {
308+
return Err(VerifyError::NoIdentity);
309+
};
310+
Ok(pk.verify(self.msg.to_byte_array(), self.sig)?)
311+
}
312+
}
313+
295314
#[derive(Debug, Display, Error, From)]
296315
#[display(doc_comments)]
297316
pub enum CertParseError {
298317
/// SSI URI lacks signature or message information.
299318
DataMissed,
300-
/// invalid fingerprint data in private key - {0}.
319+
/// invalid certificate identity fingerprint - {0}.
301320
InvalidFingerprint(Baid64ParseError),
321+
/// invalid certificate identity key - {0}.
322+
InvalidPub(Baid64ParseError),
302323
/// invalid message digest - {0}.
303324
#[from]
304325
InvalidMessage(hex::Error),
@@ -320,15 +341,26 @@ impl FromStr for SsiCert {
320341
.split_once('&')
321342
.ok_or(CertParseError::DataMissed)?;
322343
let sig = rest.trim_start_matches("sig=");
323-
let fp = Fingerprint::from_str(fp).map_err(CertParseError::InvalidFingerprint)?;
344+
let (fp, pk) = match fp.len() {
345+
8 => (Fingerprint::from_str(fp).map_err(CertParseError::InvalidFingerprint)?, None),
346+
_ => {
347+
let pk = SsiPub::from_str(fp).map_err(CertParseError::InvalidPub)?;
348+
(pk.fingerprint(), Some(pk))
349+
}
350+
};
324351
let msg = Bytes32::from_str(msg)?;
325352
let sig = SsiSig::from_str(sig)?;
326-
Ok(SsiCert { fp, msg, sig })
353+
Ok(SsiCert { fp, pk, msg, sig })
327354
}
328355
}
329356

330357
impl Display for SsiCert {
331358
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
359+
if f.alternate() {
360+
if let Some(pk) = self.pk {
361+
return write!(f, "{pk}?msg={msg}&sig={sig}", msg = self.msg, sig = self.sig);
362+
}
363+
}
332364
write!(f, "ssi:{fp}?msg={msg}&sig={sig}", fp = self.fp, msg = self.msg, sig = self.sig)
333365
}
334366
}

src/secret.rs

+1
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ impl SsiPair {
214214
let sig = self.sk.sign(digest.into());
215215
SsiCert {
216216
fp: self.pk.fingerprint(),
217+
pk: Some(self.pk),
217218
msg: Bytes32::from_byte_array(digest),
218219
sig,
219220
}

0 commit comments

Comments
 (0)