Skip to content

Commit 0ab5596

Browse files
use new pgp configuration
1 parent bd94f56 commit 0ab5596

File tree

11 files changed

+98
-40
lines changed

11 files changed

+98
-40
lines changed

src/config.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use std::process::Command;
77
use std::str::FromStr;
88
use std::sync::Arc;
99

10+
use pgp::{Deserializable, SignedPublicKey};
11+
1012
use crate::dist::{dist, temp};
1113
use crate::errors::*;
1214
use crate::notifications::*;
@@ -33,21 +35,24 @@ impl Display for OverrideReason {
3335
}
3436
}
3537

38+
lazy_static::lazy_static! {
39+
static ref BUILTIN_PGP_KEY: SignedPublicKey = pgp::SignedPublicKey::from_armor_single(
40+
io::Cursor::new(&include_bytes!("rust-key.pgp.ascii")[..])
41+
).unwrap().0;
42+
}
43+
3644
#[derive(Debug)]
3745
pub enum PgpPublicKey {
38-
Builtin(&'static [u8]),
39-
FromEnvironment(PathBuf, Vec<u8>),
40-
FromConfiguration(PathBuf, Vec<u8>),
46+
Builtin,
47+
FromEnvironment(PathBuf, SignedPublicKey),
48+
FromConfiguration(PathBuf, SignedPublicKey),
4149
}
4250

4351
impl PgpPublicKey {
44-
/// Retrieve the key data for this key
45-
///
46-
/// This key might be ASCII Armored or may not, we make no
47-
/// guarantees.
48-
pub fn key_data(&self) -> &[u8] {
52+
/// Retrieve the key.
53+
pub fn key(&self) -> &SignedPublicKey {
4954
match self {
50-
Self::Builtin(k) => k,
55+
Self::Builtin => &*BUILTIN_PGP_KEY,
5156
Self::FromEnvironment(_, k) => &k,
5257
Self::FromConfiguration(_, k) => &k,
5358
}
@@ -57,7 +62,7 @@ impl PgpPublicKey {
5762
impl Display for PgpPublicKey {
5863
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5964
match self {
60-
Self::Builtin(_) => write!(f, "builtin Rust release key"),
65+
Self::Builtin => write!(f, "builtin Rust release key"),
6166
Self::FromEnvironment(p, _) => {
6267
write!(f, "key specified in RUST_PGP_KEY ({})", p.display())
6368
}
@@ -98,18 +103,24 @@ impl Cfg {
98103
let download_dir = rustup_dir.join("downloads");
99104

100105
// PGP keys
101-
let mut pgp_keys: Vec<PgpPublicKey> =
102-
vec![PgpPublicKey::Builtin(include_bytes!("rust-key.pgp.ascii"))];
103-
if let Some(s_path) = env::var_os("RUSTUP_PGP_KEY") {
106+
let mut pgp_keys: Vec<PgpPublicKey> = vec![PgpPublicKey::Builtin];
107+
108+
if let Some(ref s_path) = env::var_os("RUSTUP_PGP_KEY") {
104109
let path = PathBuf::from(s_path);
105-
let content = utils::read_file_bytes("RUSTUP_PGP_KEY", &path)?;
106-
pgp_keys.push(PgpPublicKey::FromEnvironment(path, content));
110+
let file = utils::open_file("RUSTUP_PGP_KEY", &path)?;
111+
let (key, _) = SignedPublicKey::from_armor_single(file)
112+
.map_err(|error| ErrorKind::InvalidPgpKey(PathBuf::from(s_path), error))?;
113+
114+
pgp_keys.push(PgpPublicKey::FromEnvironment(path, key));
107115
}
108116
settings_file.with(|s| {
109117
if let Some(s) = &s.pgp_keys {
110118
let path = PathBuf::from(s);
111-
let content = utils::read_file_bytes("PGP Key from config", &path)?;
112-
pgp_keys.push(PgpPublicKey::FromConfiguration(path, content));
119+
let file = utils::open_file("PGP Key from config", &path)?;
120+
let (key, _) = SignedPublicKey::from_armor_single(file)
121+
.map_err(|error| ErrorKind::InvalidPgpKey(PathBuf::from(s), error))?;
122+
123+
pgp_keys.push(PgpPublicKey::FromConfiguration(path, key));
113124
}
114125
Ok(())
115126
})?;

src/dist/dist.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,7 @@ fn try_update_from_dist_<'a>(
844844
update_hash,
845845
&download.temp_cfg,
846846
&download.notify_handler,
847+
&download.pgp_keys,
847848
) {
848849
Ok(None) => Ok(None),
849850
Ok(Some(hash)) => Ok(Some(hash)),

src/dist/download.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
use crate::config::PgpPublicKey;
12
use crate::dist::notifications::*;
23
use crate::dist::temp;
34
use crate::errors::*;
45
use crate::utils::utils;
6+
57
use sha2::{Digest, Sha256};
68
use url::Url;
79

@@ -17,6 +19,7 @@ pub struct DownloadCfg<'a> {
1719
pub temp_cfg: &'a temp::Cfg,
1820
pub download_dir: &'a PathBuf,
1921
pub notify_handler: &'a dyn Fn(Notification<'_>),
22+
pub pgp_keys: &'a [PgpPublicKey],
2023
}
2124

2225
pub struct File {
@@ -131,6 +134,11 @@ impl<'a> DownloadCfg<'a> {
131134
}
132135

133136
fn check_signature(&self, url: &str, file: &temp::File<'_>) -> Result<()> {
137+
assert!(
138+
!self.pgp_keys.is_empty(),
139+
"At least the builtin key must be present"
140+
);
141+
134142
let signature = self.download_signature(url).map_err(|e| {
135143
e.chain_err(|| ErrorKind::SignatureVerificationFailed {
136144
url: url.to_owned(),
@@ -143,7 +151,7 @@ impl<'a> DownloadCfg<'a> {
143151
path: PathBuf::from(file_path),
144152
})?;
145153

146-
if !crate::dist::signatures::verify_signature(content, &signature)? {
154+
if !crate::dist::signatures::verify_signature(content, &signature, &self.pgp_keys)? {
147155
Err(ErrorKind::SignatureVerificationFailed {
148156
url: url.to_owned(),
149157
}

src/dist/manifestation.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Maintains a Rust installation by installing individual Rust
22
//! platform components from a distribution server.
33
4+
use crate::config::PgpPublicKey;
45
use crate::dist::component::{Components, Package, TarGzPackage, TarXzPackage, Transaction};
56
use crate::dist::config::Config;
67
use crate::dist::dist::{Profile, TargetTriple, DEFAULT_DIST_SERVER};
@@ -351,6 +352,7 @@ impl Manifestation {
351352
update_hash: Option<&Path>,
352353
temp_cfg: &temp::Cfg,
353354
notify_handler: &dyn Fn(Notification<'_>),
355+
pgp_keys: &[PgpPublicKey],
354356
) -> Result<Option<String>> {
355357
// If there's already a v2 installation then something has gone wrong
356358
if self.read_config()?.is_some() {
@@ -388,6 +390,7 @@ impl Manifestation {
388390
download_dir: &dld_dir,
389391
temp_cfg,
390392
notify_handler,
393+
pgp_keys,
391394
};
392395

393396
let dl = dlcfg.download_and_check(&url, update_hash, ".tar.gz")?;

src/dist/signatures.rs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,22 @@
33
// TODO: Determine whether we want external keyring support
44

55
use pgp::types::KeyTrait;
6-
use pgp::{Deserializable, SignedPublicKey, StandaloneSignature};
6+
use pgp::{Deserializable, StandaloneSignature};
77

8+
use crate::config::PgpPublicKey;
89
use crate::errors::*;
910

1011
use std::io::Read;
1112

12-
// const SIGNING_KEY_BYTES: &[u8] = include_bytes!("../rust-key.gpg.ascii");
13-
const SIGNING_KEY_BYTES: &[u8] = include_bytes!("../../tests/mock/signing-key.pub.asc");
14-
15-
lazy_static::lazy_static! {
16-
static ref SIGNING_KEYS: Vec<SignedPublicKey> = {
17-
pgp::SignedPublicKey::from_armor_many(std::io::Cursor::new(SIGNING_KEY_BYTES))
18-
.map_err(squish_internal_err).unwrap()
19-
.0
20-
.collect::<std::result::Result<Vec<_>, _>>()
21-
.map_err(squish_internal_err).unwrap()
22-
};
23-
}
24-
2513
fn squish_internal_err<E: std::fmt::Display>(err: E) -> Error {
2614
ErrorKind::SignatureVerificationInternalError(format!("{}", err)).into()
2715
}
2816

29-
pub fn verify_signature<T: Read>(mut content: T, signature: &str) -> Result<bool> {
17+
pub fn verify_signature<T: Read>(
18+
mut content: T,
19+
signature: &str,
20+
keys: &[PgpPublicKey],
21+
) -> Result<bool> {
3022
let mut content_buf = Vec::new();
3123
content.read_to_end(&mut content_buf)?;
3224
let (signatures, _) =
@@ -35,12 +27,13 @@ pub fn verify_signature<T: Read>(mut content: T, signature: &str) -> Result<bool
3527
for signature in signatures {
3628
let signature = signature.map_err(squish_internal_err)?;
3729

38-
for key in &*SIGNING_KEYS {
39-
if key.is_signing_key() && signature.verify(key, &content_buf).is_ok() {
30+
for key in keys {
31+
let actual_key = key.key();
32+
if actual_key.is_signing_key() && signature.verify(actual_key, &content_buf).is_ok() {
4033
return Ok(true);
4134
}
4235

43-
for sub_key in &key.public_subkeys {
36+
for sub_key in &actual_key.public_subkeys {
4437
if sub_key.is_signing_key() && signature.verify(sub_key, &content_buf).is_ok() {
4538
return Ok(true);
4639
}

src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,10 @@ error_chain! {
358358
description("bad path in tar")
359359
display("tar path '{}' is not supported", v.display())
360360
}
361+
InvalidPgpKey(v: PathBuf, error: pgp::errors::Error) {
362+
description("invalid PGP key"),
363+
display("unable to read the PGP key '{}'", v.display())
364+
}
361365
}
362366
}
363367

src/toolchain.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ impl<'a> Toolchain<'a> {
159159
temp_cfg: &self.cfg.temp_cfg,
160160
download_dir: &self.cfg.download_dir,
161161
notify_handler: &*self.dist_handler,
162+
pgp_keys: self.cfg.get_pgp_keys(),
162163
}
163164
}
164165

src/utils/utils.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ where
3737
})
3838
}
3939

40+
pub fn open_file(name: &'static str, path: &Path) -> Result<fs::File> {
41+
fs::File::open(path).chain_err(|| ErrorKind::ReadingFile {
42+
name,
43+
path: PathBuf::from(path),
44+
})
45+
}
46+
4047
pub fn read_file_bytes(name: &'static str, path: &Path) -> Result<Vec<u8>> {
4148
fs::read(path).chain_err(|| ErrorKind::ReadingFile {
4249
name,

tests/dist.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustup::errors::Result;
1616
use rustup::utils::raw as utils_raw;
1717
use rustup::utils::utils;
1818
use rustup::ErrorKind;
19+
use rustup::PgpPublicKey;
1920
use std::cell::Cell;
2021
use std::collections::HashMap;
2122
use std::fs;
@@ -523,6 +524,10 @@ fn setup_from_dist_server(
523524
temp_cfg: &temp_cfg,
524525
download_dir: &prefix.path().to_owned().join("downloads"),
525526
notify_handler: &|_| {},
527+
pgp_keys: &[PgpPublicKey::FromEnvironment(
528+
"test-key".into(),
529+
get_public_key(),
530+
)],
526531
};
527532

528533
f(url, &toolchain, &prefix, &download_cfg, &temp_cfg);
@@ -1887,6 +1892,10 @@ fn reuse_downloaded_file() {
18871892
reuse_notification_fired.set(true);
18881893
}
18891894
},
1895+
pgp_keys: &[PgpPublicKey::FromEnvironment(
1896+
"test-key".into(),
1897+
get_public_key(),
1898+
)],
18901899
};
18911900

18921901
update_from_dist(
@@ -1954,6 +1963,10 @@ fn checks_files_hashes_before_reuse() {
19541963
noticed_bad_checksum.set(true);
19551964
}
19561965
},
1966+
pgp_keys: &[PgpPublicKey::FromEnvironment(
1967+
"test-key".into(),
1968+
get_public_key(),
1969+
)],
19571970
};
19581971

19591972
update_from_dist(

tests/mock/clitools.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,14 @@ pub fn env(config: &Config, cmd: &mut Command) {
389389
// The test environment may interfere with checking the PATH for the existence of rustc or
390390
// cargo, so we disable that check globally
391391
cmd.env("RUSTUP_INIT_SKIP_PATH_CHECK", "yes");
392+
393+
// Setup pgp test key
394+
cmd.env(
395+
"RUSTUP_PGP_KEY",
396+
std::env::current_dir()
397+
.unwrap()
398+
.join("tests/mock/signing-key.pub.asc"),
399+
);
392400
}
393401

394402
use std::sync::RwLock;

tests/mock/dist.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -511,16 +511,25 @@ pub fn write_file(dst: &Path, contents: &str) {
511511
}
512512

513513
const SIGNING_KEY_BYTES: &[u8] = include_bytes!("signing-key.asc");
514+
const PUB_SIGNING_KEY_BYTES: &[u8] = include_bytes!("signing-key.pub.asc");
514515

515-
fn load_key() -> std::result::Result<pgp::SignedSecretKey, pgp::errors::Error> {
516+
fn get_secret_key() -> pgp::SignedSecretKey {
516517
use pgp::Deserializable;
517518
let (key, _) =
518-
pgp::SignedSecretKey::from_armor_single(std::io::Cursor::new(SIGNING_KEY_BYTES))?;
519-
Ok(key)
519+
pgp::SignedSecretKey::from_armor_single(std::io::Cursor::new(SIGNING_KEY_BYTES)).unwrap();
520+
key
521+
}
522+
523+
pub fn get_public_key() -> pgp::SignedPublicKey {
524+
use pgp::Deserializable;
525+
let (key, _) =
526+
pgp::SignedPublicKey::from_armor_single(std::io::Cursor::new(PUB_SIGNING_KEY_BYTES))
527+
.unwrap();
528+
key
520529
}
521530

522531
pub fn create_signature(data: &[u8]) -> std::result::Result<String, pgp::errors::Error> {
523-
let key = load_key()?;
532+
let key = get_secret_key();
524533

525534
let msg = pgp::Message::new_literal_bytes("message", data);
526535
let signed_message = msg.sign(&key, || "".into(), pgp::crypto::HashAlgorithm::SHA2_256)?;

0 commit comments

Comments
 (0)