Skip to content

Commit

Permalink
Merge pull request #114 from nox/nox/openssl-fixes
Browse files Browse the repository at this point in the history
Port security fixes from the openssl crate (fixes #111)
  • Loading branch information
inikulin authored May 11, 2023
2 parents ec52371 + b36b170 commit da32be1
Show file tree
Hide file tree
Showing 4 changed files with 423 additions and 96 deletions.
78 changes: 78 additions & 0 deletions boring/src/asn1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use crate::bio::MemBio;
use crate::bn::{BigNum, BigNumRef};
use crate::error::ErrorStack;
use crate::nid::Nid;
use crate::stack::Stackable;
use crate::string::OpensslString;
use crate::{cvt, cvt_p};

Expand Down Expand Up @@ -78,6 +79,79 @@ impl fmt::Display for Asn1GeneralizedTimeRef {
}
}

/// The type of an ASN.1 value.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Asn1Type(c_int);

#[allow(missing_docs)] // no need to document the constants
impl Asn1Type {
pub const EOC: Asn1Type = Asn1Type(ffi::V_ASN1_EOC);

pub const BOOLEAN: Asn1Type = Asn1Type(ffi::V_ASN1_BOOLEAN);

pub const INTEGER: Asn1Type = Asn1Type(ffi::V_ASN1_INTEGER);

pub const BIT_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_BIT_STRING);

pub const OCTET_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_OCTET_STRING);

pub const NULL: Asn1Type = Asn1Type(ffi::V_ASN1_NULL);

pub const OBJECT: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT);

pub const OBJECT_DESCRIPTOR: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT_DESCRIPTOR);

pub const EXTERNAL: Asn1Type = Asn1Type(ffi::V_ASN1_EXTERNAL);

pub const REAL: Asn1Type = Asn1Type(ffi::V_ASN1_REAL);

pub const ENUMERATED: Asn1Type = Asn1Type(ffi::V_ASN1_ENUMERATED);

pub const UTF8STRING: Asn1Type = Asn1Type(ffi::V_ASN1_UTF8STRING);

pub const SEQUENCE: Asn1Type = Asn1Type(ffi::V_ASN1_SEQUENCE);

pub const SET: Asn1Type = Asn1Type(ffi::V_ASN1_SET);

pub const NUMERICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_NUMERICSTRING);

pub const PRINTABLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_PRINTABLESTRING);

pub const T61STRING: Asn1Type = Asn1Type(ffi::V_ASN1_T61STRING);

pub const TELETEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_TELETEXSTRING);

pub const VIDEOTEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VIDEOTEXSTRING);

pub const IA5STRING: Asn1Type = Asn1Type(ffi::V_ASN1_IA5STRING);

pub const UTCTIME: Asn1Type = Asn1Type(ffi::V_ASN1_UTCTIME);

pub const GENERALIZEDTIME: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALIZEDTIME);

pub const GRAPHICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GRAPHICSTRING);

pub const ISO64STRING: Asn1Type = Asn1Type(ffi::V_ASN1_ISO64STRING);

pub const VISIBLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VISIBLESTRING);

pub const GENERALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALSTRING);

pub const UNIVERSALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_UNIVERSALSTRING);

pub const BMPSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_BMPSTRING);

/// Constructs an `Asn1Type` from a raw OpenSSL value.
pub fn from_raw(value: c_int) -> Self {
Asn1Type(value)
}

/// Returns the raw OpenSSL value represented by this type.
pub fn as_raw(&self) -> c_int {
self.0
}
}

/// Difference between two ASN1 times.
///
/// This `struct` is created by the [`diff`] method on [`Asn1TimeRef`]. See its
Expand Down Expand Up @@ -482,6 +556,10 @@ foreign_type_and_impl_send_sync! {
pub struct Asn1Object;
}

impl Stackable for Asn1Object {
type StackType = ffi::stack_st_ASN1_OBJECT;
}

impl Asn1Object {
/// Constructs an ASN.1 Object Identifier from a string representation of
/// the OID.
Expand Down
156 changes: 68 additions & 88 deletions boring/src/x509/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
//! ```
use std::fmt::Write;

use crate::asn1::Asn1Object;
use crate::error::ErrorStack;
use crate::nid::Nid;
use crate::x509::{X509Extension, X509v3Context};
use crate::x509::{GeneralName, Stack, X509Extension, X509v3Context};
use foreign_types::ForeignType;

/// An extension which indicates whether a certificate is a CA certificate.
pub struct BasicConstraints {
Expand Down Expand Up @@ -221,18 +223,7 @@ impl KeyUsage {
/// for which the certificate public key can be used for.
pub struct ExtendedKeyUsage {
critical: bool,
server_auth: bool,
client_auth: bool,
code_signing: bool,
email_protection: bool,
time_stamping: bool,
ms_code_ind: bool,
ms_code_com: bool,
ms_ctl_sign: bool,
ms_sgc: bool,
ms_efs: bool,
ns_sgc: bool,
other: Vec<String>,
items: Vec<String>,
}

impl Default for ExtendedKeyUsage {
Expand All @@ -246,18 +237,7 @@ impl ExtendedKeyUsage {
pub fn new() -> ExtendedKeyUsage {
ExtendedKeyUsage {
critical: false,
server_auth: false,
client_auth: false,
code_signing: false,
email_protection: false,
time_stamping: false,
ms_code_ind: false,
ms_code_com: false,
ms_ctl_sign: false,
ms_sgc: false,
ms_efs: false,
ns_sgc: false,
other: vec![],
items: vec![],
}
}

Expand All @@ -269,95 +249,69 @@ impl ExtendedKeyUsage {

/// Sets the `serverAuth` flag to `true`.
pub fn server_auth(&mut self) -> &mut ExtendedKeyUsage {
self.server_auth = true;
self
self.other("serverAuth")
}

/// Sets the `clientAuth` flag to `true`.
pub fn client_auth(&mut self) -> &mut ExtendedKeyUsage {
self.client_auth = true;
self
self.other("clientAuth")
}

/// Sets the `codeSigning` flag to `true`.
pub fn code_signing(&mut self) -> &mut ExtendedKeyUsage {
self.code_signing = true;
self
self.other("codeSigning")
}

/// Sets the `timeStamping` flag to `true`.
pub fn time_stamping(&mut self) -> &mut ExtendedKeyUsage {
self.time_stamping = true;
self
self.other("timeStamping")
}

/// Sets the `msCodeInd` flag to `true`.
pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage {
self.ms_code_ind = true;
self
self.other("msCodeInd")
}

/// Sets the `msCodeCom` flag to `true`.
pub fn ms_code_com(&mut self) -> &mut ExtendedKeyUsage {
self.ms_code_com = true;
self
self.other("msCodeCom")
}

/// Sets the `msCTLSign` flag to `true`.
pub fn ms_ctl_sign(&mut self) -> &mut ExtendedKeyUsage {
self.ms_ctl_sign = true;
self
self.other("msCTLSign")
}

/// Sets the `msSGC` flag to `true`.
pub fn ms_sgc(&mut self) -> &mut ExtendedKeyUsage {
self.ms_sgc = true;
self
self.other("msSGC")
}

/// Sets the `msEFS` flag to `true`.
pub fn ms_efs(&mut self) -> &mut ExtendedKeyUsage {
self.ms_efs = true;
self
self.other("msEFS")
}

/// Sets the `nsSGC` flag to `true`.
pub fn ns_sgc(&mut self) -> &mut ExtendedKeyUsage {
self.ns_sgc = true;
self
self.other("nsSGC")
}

/// Sets a flag not already defined.
pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage {
self.other.push(other.to_owned());
self.items.push(other.to_string());
self
}

/// Return the `ExtendedKeyUsage` extension as an `X509Extension`.
pub fn build(&self) -> Result<X509Extension, ErrorStack> {
let mut value = String::new();
let mut first = true;
append(&mut value, &mut first, self.critical, "critical");
append(&mut value, &mut first, self.server_auth, "serverAuth");
append(&mut value, &mut first, self.client_auth, "clientAuth");
append(&mut value, &mut first, self.code_signing, "codeSigning");
append(
&mut value,
&mut first,
self.email_protection,
"emailProtection",
);
append(&mut value, &mut first, self.time_stamping, "timeStamping");
append(&mut value, &mut first, self.ms_code_ind, "msCodeInd");
append(&mut value, &mut first, self.ms_code_com, "msCodeCom");
append(&mut value, &mut first, self.ms_ctl_sign, "msCTLSign");
append(&mut value, &mut first, self.ms_sgc, "msSGC");
append(&mut value, &mut first, self.ms_efs, "msEFS");
append(&mut value, &mut first, self.ns_sgc, "nsSGC");
for other in &self.other {
append(&mut value, &mut first, true, other);
let mut stack = Stack::new()?;
for item in &self.items {
stack.push(Asn1Object::from_str(item)?)?;
}
unsafe {
X509Extension::new_internal(Nid::EXT_KEY_USAGE, self.critical, stack.as_ptr().cast())
}
X509Extension::new_nid(None, None, Nid::EXT_KEY_USAGE, &value)
}
}

Expand Down Expand Up @@ -456,11 +410,19 @@ impl AuthorityKeyIdentifier {
}
}

enum RustGeneralName {
Dns(String),
Email(String),
Uri(String),
Ip(String),
Rid(String),
}

/// An extension that allows additional identities to be bound to the subject
/// of the certificate.
pub struct SubjectAlternativeName {
critical: bool,
names: Vec<String>,
items: Vec<RustGeneralName>,
}

impl Default for SubjectAlternativeName {
Expand All @@ -474,7 +436,7 @@ impl SubjectAlternativeName {
pub fn new() -> SubjectAlternativeName {
SubjectAlternativeName {
critical: false,
names: vec![],
items: vec![],
}
}

Expand All @@ -486,55 +448,73 @@ impl SubjectAlternativeName {

/// Sets the `email` flag.
pub fn email(&mut self, email: &str) -> &mut SubjectAlternativeName {
self.names.push(format!("email:{}", email));
self.items.push(RustGeneralName::Email(email.to_string()));
self
}

/// Sets the `uri` flag.
pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName {
self.names.push(format!("URI:{}", uri));
self.items.push(RustGeneralName::Uri(uri.to_string()));
self
}

/// Sets the `dns` flag.
pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName {
self.names.push(format!("DNS:{}", dns));
self.items.push(RustGeneralName::Dns(dns.to_string()));
self
}

/// Sets the `rid` flag.
pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName {
self.names.push(format!("RID:{}", rid));
self.items.push(RustGeneralName::Rid(rid.to_string()));
self
}

/// Sets the `ip` flag.
pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName {
self.names.push(format!("IP:{}", ip));
self.items.push(RustGeneralName::Ip(ip.to_string()));
self
}

/// Sets the `dirName` flag.
pub fn dir_name(&mut self, dir_name: &str) -> &mut SubjectAlternativeName {
self.names.push(format!("dirName:{}", dir_name));
self
///
/// Not currently actually supported, always panics.
#[deprecated = "dir_name is deprecated and always panics. Please file a bug if you have a use case for this."]
pub fn dir_name(&mut self, _dir_name: &str) -> &mut SubjectAlternativeName {
unimplemented!(
"This has not yet been adapted for the new internals. File a bug if you need this."
);
}

/// Sets the `otherName` flag.
pub fn other_name(&mut self, other_name: &str) -> &mut SubjectAlternativeName {
self.names.push(format!("otherName:{}", other_name));
self
///
/// Not currently actually supported, always panics.
#[deprecated = "other_name is deprecated and always panics. Please file a bug if you have a use case for this."]
pub fn other_name(&mut self, _other_name: &str) -> &mut SubjectAlternativeName {
unimplemented!(
"This has not yet been adapted for the new internals. File a bug if you need this."
);
}

/// Return a `SubjectAlternativeName` extension as an `X509Extension`.
pub fn build(&self, ctx: &X509v3Context) -> Result<X509Extension, ErrorStack> {
let mut value = String::new();
let mut first = true;
append(&mut value, &mut first, self.critical, "critical");
for name in &self.names {
append(&mut value, &mut first, true, name);
pub fn build(&self, _ctx: &X509v3Context<'_>) -> Result<X509Extension, ErrorStack> {
let mut stack = Stack::new()?;
for item in &self.items {
let gn = match item {
RustGeneralName::Dns(s) => GeneralName::new_dns(s.as_bytes())?,
RustGeneralName::Email(s) => GeneralName::new_email(s.as_bytes())?,
RustGeneralName::Uri(s) => GeneralName::new_uri(s.as_bytes())?,
RustGeneralName::Ip(s) => {
GeneralName::new_ip(s.parse().map_err(|_| ErrorStack::get())?)?
}
RustGeneralName::Rid(s) => GeneralName::new_rid(Asn1Object::from_str(s)?)?,
};
stack.push(gn)?;
}

unsafe {
X509Extension::new_internal(Nid::SUBJECT_ALT_NAME, self.critical, stack.as_ptr().cast())
}
X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_ALT_NAME, &value)
}
}

Expand Down
Loading

0 comments on commit da32be1

Please sign in to comment.