summaryrefslogtreecommitdiffstats
path: root/openpgp-ffi/src/packet
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2019-11-06 14:42:50 +0100
committerNeal H. Walfield <neal@pep.foundation>2019-11-06 15:21:12 +0100
commit8693a005c08e1c84d693fe7baa154f8785007520 (patch)
treed5e65fad35a3137db184562e886e4b2a9fa7111d /openpgp-ffi/src/packet
parent0fdb21c2f446234570c8935ada9f29c7f6392b98 (diff)
openpgp: Replace RFC 2822 parser with a de factor parser
- RFC 4880 says that "by convention, [a User ID Packet] includes an RFC 2822 [RFC2822] mail name-addr." This is not the actual convention, and attempting to parse User IDs using an RFC 2822 parser means that many common User IDs cannot be parsed. - Disparities between the actual convention and the stated convention include: - Neither users nor the software they use to create keys correctly quotes User IDs: - 'Nachname, Vorname <name@example.org>' is not valid, because it contains an unquoted comma. It should be 'Nachname\, Vorname <name@example.org>' or '"Nachname, Vorname" <name@example.org>'. (The same goes for dots, single quotes, etc.) - 'user@example.org <user@example.org>' is not valid, because it contains an unquoted at symbol. - 'Bj=?utf-8?q?=C3=B6?=rn <bjoern@example.net>' is encoded using RFC 2047, which is what RFC 2822 mandates when using non-ASCII characters, but no OpenPGP software would decode this User ID. In practice, everyone just uses UTF-8 (in this case: 'Björn <bjoern@example.net>'). - There are many examples of User IDs containing raw email addresses ('user@example.org'). But, these are not "name-addr"s. At best, they are RFC 2822 "mailbox"es. - Some User IDs only contain a name (e.g, "Frank PGP"). - RFC 2822 also includes a lot of complexity that no one uses or needs. For instance, CFWS (comments and folding whitespace) can be placed everywhere, and the rules for parsing them are complex. - Instead of continuing to bend the RFC 2822 parser to our will, we instead accept reality. - This patch replaces the RFC 2822 parser with a significantly simpler parser, which is based on actual convention (i.e., User IDs in the wild). - This parser is based on dkg's mail to the OpenPGP working group mailing list. Message-ID: <87woe7zx7o.fsf@fifthhorseman.net> https://mailarchive.ietf.org/arch/msg/openpgp/wNo27-0STfGR9JZSlC7s6OYOJkI - This initial version has one notable regression with respect to the RFC 2822 parser: it doesn't handle User IDs holding URIs.
Diffstat (limited to 'openpgp-ffi/src/packet')
-rw-r--r--openpgp-ffi/src/packet/userid.rs187
1 files changed, 25 insertions, 162 deletions
diff --git a/openpgp-ffi/src/packet/userid.rs b/openpgp-ffi/src/packet/userid.rs
index 69edf50c..168227c4 100644
--- a/openpgp-ffi/src/packet/userid.rs
+++ b/openpgp-ffi/src/packet/userid.rs
@@ -27,11 +27,8 @@ fn pgp_user_id_new(value: *const c_char)
/// Constructs a User ID.
///
-/// This escapes the name. The comment and address must be well
-/// formed according to RFC 2822. Only the address is required.
-///
-/// If you already have a full RFC 2822 mailbox, then you can just
-/// use `UserID::from()`.
+/// This does a basic check and any necessary escaping to form a de
+/// factor User ID. Only the address is required.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
pub extern "C"
fn pgp_user_id_from_address(
@@ -63,14 +60,11 @@ fn pgp_user_id_from_address(
/// Constructs a User ID.
///
-/// This escapes the name. The comment must be well formed, the
-/// address can be arbitrary.
+/// This does a basic check and any necessary escaping to form a de
+/// factor User ID. The address is not checked.
///
/// This is useful when you want to specify a URI instead of an
/// email address.
-///
-/// If you have a full RFC 2822 mailbox, then you can just use
-/// `UserID::from()`.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
pub extern "C"
fn pgp_user_id_from_unchecked_address(
@@ -132,23 +126,15 @@ fn pgp_user_id_value(uid: *const Packet, value_len: Option<&mut size_t>)
}
}
-/// Returns the User ID's display name, if any.
-///
-/// The User ID is parsed as an [RFC 2822 mailbox], and the display
-/// name is extracted.
-///
-/// Note: invalid email addresses are accepted in order to support
-/// things like URIs of the form `Hostname
-/// <ssh://server@example.net>`.
-///
-/// If the User ID is otherwise not a valid RFC 2822 mailbox
-/// production, then an error is returned.
+/// Returns the User ID's name component, if any.
///
+/// The User ID is parsed according to de factor convention, and the
+/// name component is extracted.
///
-/// If the User ID does not contain a display, *name is set
-/// to NULL.
+/// If the User ID cannot be parsed, then an error is returned.
///
-/// [RFC 2822 mailbox]: https://tools.ietf.org/html/rfc2822#section-3.4
+/// If the User ID does not contain a name component, *namep is set to
+/// NULL.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
pub extern "C"
fn pgp_user_id_name(
@@ -181,22 +167,15 @@ fn pgp_user_id_name(
Status::Success
}
-/// Returns the User ID's comment, if any.
-///
-/// The User ID is parsed as an [RFC 2822 mailbox], and the first
-/// comment is extracted.
+/// Returns the User ID's comment field, if any.
///
-/// Note: invalid email addresses are accepted in order to support
-/// things like URIs of the form `Hostname
-/// <ssh://server@example.net>`.
+/// The User ID is parsed according to de factor convention, and the
+/// comment field is extracted.
///
-/// If the User ID is otherwise not a valid RFC 2822 mailbox
-/// production, then an error is returned.
+/// If the User ID cannot be parsed, then an error is returned.
///
/// If the User ID does not contain a comment, *commentp is set
/// to NULL.
-///
-/// [RFC 2822 mailbox]: https://tools.ietf.org/html/rfc2822#section-3.4
#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
pub extern "C"
fn pgp_user_id_comment(
@@ -231,23 +210,16 @@ fn pgp_user_id_comment(
/// Returns the User ID's email address, if any.
///
-/// The User ID is parsed as an [RFC 2822 mailbox], and the email
-/// address is extracted.
+/// The User ID is parsed according to de factor convention, and the
+/// email address is extracted.
///
-/// Note: invalid email addresses are accepted in order to support
-/// things like URIs of the form `Hostname
-/// <ssh://server@example.net>`.
-///
-/// If the User ID is otherwise not a valid RFC 2822 mailbox
-/// production, then an error is returned.
+/// If the User ID cannot be parsed, then an error is returned.
///
/// If the User ID does not contain an email address, *addressp is set
/// to NULL.
-///
-/// [RFC 2822 mailbox]: https://tools.ietf.org/html/rfc2822#section-3.4
#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
pub extern "C"
-fn pgp_user_id_address(
+fn pgp_user_id_email(
errp: Option<&mut *mut crate::error::Error>, uid: *const Packet,
addressp: &mut *mut c_char)
-> Status
@@ -256,7 +228,7 @@ fn pgp_user_id_address(
let uid = uid.ref_raw();
if let &openpgp::Packet::UserID(ref uid) = uid {
- match uid.address() {
+ match uid.email() {
Ok(Some(address)) =>
*addressp = ffi_return_string!(address),
Ok(None) =>
@@ -277,115 +249,6 @@ fn pgp_user_id_address(
Status::Success
}
-/// Returns the User ID's invalid address, if any.
-///
-/// The User ID is parsed as an [RFC 2822 mailbox], and if the address
-/// is invalid, that is returned.
-///
-/// Note: invalid email addresses are accepted in order to support
-/// things like URIs of the form `Hostname
-/// <ssh://server@example.net>`.
-///
-/// If the User ID is otherwise not a valid RFC 2822 mailbox
-/// production, then an error is returned.
-///
-/// If the User ID does not contain an invalid address, *otherp is
-/// set to NULL.
-///
-/// [RFC 2822 mailbox]: https://tools.ietf.org/html/rfc2822#section-3.4
-#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
-pub extern "C"
-fn pgp_user_id_other(
- errp: Option<&mut *mut crate::error::Error>, uid: *const Packet,
- otherp: &mut *mut c_char)
- -> Status
-{
- ffi_make_fry_from_errp!(errp);
- let uid = uid.ref_raw();
-
- if let &openpgp::Packet::UserID(ref uid) = uid {
- match uid.other() {
- Ok(Some(other)) =>
- *otherp = ffi_return_string!(other),
- Ok(None) =>
- *otherp = ::std::ptr::null_mut(),
- Err(err) => {
- use crate::MoveIntoRaw;
- let status = crate::error::Status::from(&err);
- if let Some(errp) = errp {
- *errp = err.move_into_raw();
- }
- return status;
- }
- }
- } else {
- panic!("Not a UserID packet");
- }
-
- Status::Success
-}
-
-/// Returns the User ID's email address, if any.
-///
-/// The User ID is parsed as an [RFC 2822 mailbox], and the email
-/// address, whether it is valid or not, is extracted.
-///
-/// Note: invalid email addresses are accepted in order to support
-/// things like URIs of the form `Hostname
-/// <ssh://server@example.net>`.
-///
-/// If the User ID is otherwise not a valid RFC 2822 mailbox
-/// production, then an error is returned.
-///
-/// If the User ID does not contain an address (valid or invalid),
-/// *addressp is set to NULL.
-///
-/// [RFC 2822 mailbox]: https://tools.ietf.org/html/rfc2822#section-3.4
-#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
-pub extern "C"
-fn pgp_user_id_address_or_other(
- errp: Option<&mut *mut crate::error::Error>, uid: *const Packet,
- addressp: &mut *mut c_char)
- -> Status
-{
- ffi_make_fry_from_errp!(errp);
- let uid = uid.ref_raw();
-
- if let &openpgp::Packet::UserID(ref uid) = uid {
- match uid.address() {
- Ok(Some(address)) =>
- *addressp = ffi_return_string!(address),
- Ok(None) =>
- match uid.other() {
- Ok(Some(other)) =>
- *addressp = ffi_return_string!(other),
- Ok(None) =>
- *addressp = ::std::ptr::null_mut(),
- Err(err) => {
- use crate::MoveIntoRaw;
- let status = crate::error::Status::from(&err);
- if let Some(errp) = errp {
- *errp = err.move_into_raw();
- }
- return status;
- }
- },
- Err(err) => {
- use crate::MoveIntoRaw;
- let status = crate::error::Status::from(&err);
- if let Some(errp) = errp {
- *errp = err.move_into_raw();
- }
- return status;
- }
- }
- } else {
- panic!("Not a UserID packet");
- }
-
- Status::Success
-}
-
/// Returns a normalized version of the UserID's email address.
///
/// Normalized email addresses are primarily needed when email
@@ -406,20 +269,20 @@ fn pgp_user_id_address_or_other(
/// [Autocrypt]: https://autocrypt.org/level1.html#e-mail-address-canonicalization
#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
pub extern "C"
-fn pgp_user_id_address_normalized(
+fn pgp_user_id_email_normalized(
errp: Option<&mut *mut crate::error::Error>, uid: *const Packet,
- addressp: &mut *mut c_char)
+ emailp: &mut *mut c_char)
-> Status
{
ffi_make_fry_from_errp!(errp);
let uid = uid.ref_raw();
if let &openpgp::Packet::UserID(ref uid) = uid {
- match uid.address_normalized() {
- Ok(Some(address)) =>
- *addressp = ffi_return_string!(address),
+ match uid.email_normalized() {
+ Ok(Some(email)) =>
+ *emailp = ffi_return_string!(email),
Ok(None) =>
- *addressp = ::std::ptr::null_mut(),
+ *emailp = ::std::ptr::null_mut(),
Err(err) => {
use crate::MoveIntoRaw;
let status = crate::error::Status::from(&err);