rust-lang / rustup

The Rust toolchain installer
https://rust-lang.github.io/rustup/
Apache License 2.0
6.1k stars 877 forks source link

SHA1 PGP signatures aren't supported anymore #3185

Open g2p opened 1 year ago

g2p commented 1 year ago

Problem

As described here: https://www.reddit.com/r/rust/comments/10qlf1q/nightly_dc1d9d50f_20230131_signature_verification/

rustup update and rustup check report that https://static.rust-lang.org/dist/channel-rust-nightly.toml / https://static.rust-lang.org/dist/channel-rust-nightly.toml.asc aren't valid anymore.

Steps

rustup check

751.7 KiB / 751.7 KiB (100 %) 719.4 KiB/s in  1s ETA:  0s
warning: Signature verification failed for 'https://static.rust-lang.org/dist/channel-rust-nightly.toml'
nightly-x86_64-unknown-linux-gnu - Update available : 1.69.0-nightly (001a77fac 2023-01-30) -> 1.69.0-nightly (dc1d9d50f 2023-01-31)
rustup update
rustup update nightly
info: syncing channel updates for 'nightly-x86_64-unknown-linux-gnu'
warning: Signature verification failed for 'https://static.rust-lang.org/dist/channel-rust-nightly.toml'
info: latest update on 2023-02-01, rust version 1.69.0-nightly (dc1d9d50f 2023-01-31)
^C

Manually

cd ~/src/github.com/rust-lang/rustup
curl -O https://static.rust-lang.org/dist/channel-rust-nightly.toml
curl -O https://static.rust-lang.org/dist/channel-rust-nightly.toml.asc
sqv --keyring src/rust-key.pgp.ascii channel-rust-nightly.toml{.asc,}
Signing key on 108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE is not bound:
           No binding signature at time 2023-02-01T00:44:45Z
  because: Policy rejected non-revocation signature (PositiveCertification) requiring second pre-image resistance
  because: SHA1 is not considered secure since 2023-02-01T00:00:00Z

sqv is from cargo install sequoia-sqv.

Possible Solution(s)

This should be fixed outside rustup, but I don't know where to file a report on the release process. Please switch away from using SHA1 in keys or signatures.

Notes

No response

Rustup version

rustup --version
rustup 1.25.1 (bb60b1e89 2022-07-12)

Installed toolchains

nightly-x86_64-unknown-linux-gnu
pietroalbini commented 1 year ago

Working on a fix.

pietroalbini commented 1 year ago

Thanks for investigating this! I opened a PR that should suppress the warning, hopefully we'll be able to release a new Rustup version with that today. https://github.com/rust-lang/rustup/pull/3186

reillysiemens commented 1 year ago

Thanks for being so on top of this, @pietroalbini!

rbtcollins commented 1 year ago

Do we need to do more work here (e.g. switch to a stronger hash in the infra channels, and resign older releases?)

bjorn3 commented 1 year ago

As I understand it SHA1 is used as part of signing subkeys of the root signing key. It isn't used as part of signing the actual release tarballs.

nwalfield commented 1 year ago

Do we need to do more work here (e.g. switch to a stronger hash in the infra channels, and resign older releases?)

It would be good to update the signing certificate so that it is valid without SHA-1. This can be done with e.g. sq-keyring-linter --fix.

Ideally, rustup would also opportunistically download the certificate in order to get updates, e.g., from https://rustup.rs/root.pgp and from https://keys.openpgp.org. Since the certificate is pinned in rustup, an attacker may be able to withhold updates (although this is mitigate partially by checking for updates from multiple locations), but they won't be able to trick the user into using the wrong certificate.

kpcyrd commented 1 year ago

Be careful when refreshing update keys out of band, this should only update existing keys but reject any new subkeys to not break future update transparency efforts.

nwalfield commented 1 year ago

Be careful when refreshing update keys out of band, this should only update existing keys but reject any new subkeys to not break future update transparency efforts.

Why should new subkeys be rejected?

kpcyrd commented 1 year ago

The rust release key rust-key@rust-lang.org is currently setup like this (although the first one is technically not a subkey):

108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE  Rust Language (Tag and Release Signing Key) <rust-key@rust-lang.org>
108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE  Subkey 108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE
108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE  Subkey C13466B7E169A085188632165CB4A9347B3B09DC
108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE  Subkey 29D57CE15D76E78CD57D326A8E9AA3F7AB3F5826

Or in gpg output:

% gpg --fingerprint --fingerprint --list-keys 108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE
pub   rsa4096 2013-09-26 [SC]
      108F 6620 5EAE B0AA A8DD  5E1C 85AB 96E6 FA1B E5FE
uid           [ unknown] Rust Language (Tag and Release Signing Key) <rust-key@rust-lang.org>
sub   rsa4096 2013-09-26 [E]
      29D5 7CE1 5D76 E78C D57D  326A 8E9A A3F7 AB3F 5826
sub   rsa4096 2014-12-15 [S]
      C134 66B7 E169 A085 1886  3216 5CB4 A934 7B3B 09DC

This means the following keys can issue signatures for updates and need to be monitored (I guess the encryption-only key can be ignored):

108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE
C13466B7E169A085188632165CB4A9347B3B09DC

This is currently hard-coded into the rustup binary, as long as I can ensure the user has a legitimate copy of rustup I can be sure it's going to attempt to enforce this policy.

Now if we allow subkey updates (essentially "if we allow delegation of trust"), somebody with access to 108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE could issue a new subkey (we're going to refer to it as 1337133713371337133713371337133713371337) that also has the signing capability enabled. If the person we're targeting downloads this key (or especially if it's going to saved to ~/.rustup), their new set of trusted keys that can issue signatures for updates looks like this:

108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE
C13466B7E169A085188632165CB4A9347B3B09DC
1337133713371337133713371337133713371337

But because you don't know about this secret subkey you're still monitoring the transparency log for these two keys:

108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE
C13466B7E169A085188632165CB4A9347B3B09DC

This means I could safely submit my malicious update (signed by 1337133713371337133713371337133713371337) to the transparency log and get inclusion proof without setting of any alarms. Even if the signature gets discovered during the attack it would be very difficult to detect the key compromise itself because you can't know if the signature from 1337133713371337133713371337133713371337 has any trust delegated to it unless you also know the content of ~/.rustup of the user I'm targeting.

nwalfield commented 1 year ago

Thanks for your write up. What transparency log are you talking about? I wasn't aware that rustup was using that.

kpcyrd commented 1 year ago

(This went slightly off-topic, feel free to skip to the next section):

rustup itself isn't using any transparency log, there are two projects attempting to do this for pgp-in-general though:

Searching for the public rekor log currently yields one entry for the rust release key (src/rust-key.pgp.ascii is located in the rustup repository):

% rekor-cli search --public-key src/rust-key.pgp.ascii
Found matching entries (listed by UUID):
24296fb24b8ad77a49f171daa9a8b39041e6b36ec74785714cead6b07b7293d910440c751875550d

Inspecting the entry shows it's a signature over the sha256 hash 642f09caa48e97de84958f8d4da5160ca298b94bf5360ba12c15be72877d487a:

``` % rekor-cli get --uuid 24296fb24b8ad77a49f171daa9a8b39041e6b36ec74785714cead6b07b7293d910440c751875550d LogID: c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d Index: 12409326 IntegratedTime: 2023-02-01T13:51:48Z UUID: 24296fb24b8ad77a49f171daa9a8b39041e6b36ec74785714cead6b07b7293d910440c751875550d Body: { "RekordObj": { "data": { "hash": { "algorithm": "sha256", "value": "642f09caa48e97de84958f8d4da5160ca298b94bf5360ba12c15be72877d487a" } }, "signature": { "content": "LS0tLS1CRUdJTiBQR1AgU0lHTkFUVVJFLS0tLS0KCndzRmNCQUFCQ2dBUUJRSmoyYlg5Q1JDRnE1Ym0raHZsL2dBQUdiVVAvQWhoYS9GU3hqQitSL0RRWTArSExZVTgKMy81MEFqWGpyRFhwZ0JoV0YwbTJoTjJkVWxsZXdUNTV0R2JOdzNJeUduSmQwRmxNZWZtTU1EVkswM081aFphcwpxdFVhbXVWUTZDYWRVSm4xVGtpdzZESnowSTRJd3hpQWJlNlB5NmJ6WjhUNHZwcWVGUE9BajRsR0dNNS82eFZsCm5FNXJnK1pUY09na1hlZFdsZkNpY1J4TmJTVmtFYTNsczVJbWtrRU04bW9uc1JjRmszZXRVOUJ2aG1MSWNVSk0KMlVaRU1KWHlwUjk3REh5WWN2TkNFdE5RaWw1Z1NscVZaZXFFUlY0VmFZanNkZnVtS0lnUWoxQjAzQ3BZcEUwZgpyL29sR3BUNjk1ZFhUV2FsbVp4aWg5RTU1czkvVTFETlpvcXU1b3FzWG56T3VsVC9MV2lsVzI2KzltRXhyZDFKCkZPdi9iTW5WUFNNMEJFbVEzRFp5L2IrVmNTY09jcDMvMEhMOXREZmtWTjliQ3g5aTlENlEzUkYxMDNhVmY3NWQKLzVZdENScFIyaWhQYlovZkxxWk5SSkdGSHRsVlljK2ZxTzdKRXRxOTdEdnY0Wkg0RStETE5oMGYvT1lYdG1XbwpUNXRjSURyQ0lGaGROQ2ZEa2VONWt5Zk4wZjdDWERYQUhZQnRUMHFkb0U4VExsNzdFRFhVNzl0S3BxYUxwczMyCmIzYnF0SHFKbkVvUlZ5c2tXRnJUZk5pQ2k0MTdGL0t0N2ljMGlGSWxIVURJWHhOcVVSQWhvOVhobkwrb3dodEwKVjlxRHcvelBnZWt5eUNqU2FsNjhJV3hUSUtUTDFtLzJVOEhNSTJNdXV1VVpjYm1qUkJDanIrZE52bEtSSU51aQpIR04rcFo5TFFCazI5NEhKWlNRUwo9eEFkbQotLS0tLUVORCBQR1AgU0lHTkFUVVJFLS0tLS0K", "format": "pgp", "publicKey": { "content": "LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tCgp4c0ZOQkZKRXdNa0JFQURsUEFDYTJLN3JlRDR4NXpkOGFmS3g3NVFZS214cVp3eXdSYmdlSUNlRDRiS2lRb0paCmRVam1uMUxnckdhWHVCTUtYSlFoeUEzNGUvMVlaZWwvOGV0K0hQRTVYcGxqQmZOWVhXYlZvY0UxVU1VVG5GVTkKQ0tYYTRBaEozM2Y3d2UyL1FtTlJNVWlmdzVhZFB3R01nNEQ4Y0RLWGswMk5kbnFRbG1GQnl2MHZTYUFyUjVrbgpnWktuTFk2bzB6WjlCdXl5NzYxSW0vU2hYcXY0QVRVZ1lpRmM0OHozM0c0aitCRG1uMHJ5R3IxYUZkUDU4dEhwCmdqV3RMWnMwaVdlRk5SRFlEamU2T0R5dS9Nak95dUFXYjJwWURINDdYdTdYZWRNWnplbkgyVExNOXl0L2h5T1YKeFJlRFBodm9Ha2FPOHhxSGlvSk1vUFFpMWdCanVCZWV3bUZ5VFNQUzRkZUFTdWtoQ0ZPY1Rzdy9lbnpKYWdpUwpaQXE2SW1laGR1a2UrcGVBTDF6NFB1Um16RFBPMkxQaFZTN0NEWHR1S0FZcVVWMllha1RxOE1aVWVtcFZodzVuCkxxVmFKNS9YaXlPY3Y0MDVQbmtUMjVlSVZWVmdoeEFneXo2Yk9VL1VNakdRWWxrVXhJN1laOXRkcmVMbEZ5UFIKT1VMMzBFOHEvYUNkNFBHSlYyNHlKMXVpdCt5Uzh4anlVaU1LbTRKN29NUDJYZEJOOThUVWZMR3c3U0tlQXh5VQo5MkJIbHhnN3l5UGZJNFRnbHNDem9TZ0VJVjZ4b0dPVlJSQ1lsR3pTalVmejBiQ01DY2xoVFFSQmtlZ0tjakIzCnNNVHlHM1NQWmJqVGxDcXJGSHkxM2U2aEdsMzdOaHM4L012WFV5c3EyY2x1RUlTbjViaXZUS0VlZVFBUkFRQUIKelVSU2RYTjBJRXhoYm1kMVlXZGxJQ2hVWVdjZ1lXNWtJRkpsYkdWaGMyVWdVMmxuYm1sdVp5QkxaWGtwSUR4eQpkWE4wTFd0bGVVQnlkWE4wTFd4aGJtY3ViM0puUHNMQmVBUVRBUUlBSWdVQ1VrVEF5UUliQXdZTENRZ0hBd0lHCkZRZ0NDUW9MQkJZQ0F3RUNIZ0VDRjRBQUNna1FoYXVXNXZvYjVmNWZZUS8vYjFEV0sxTlNHeDVuWjN6WVplSEoKOW13R0NmdElhQTJJUmdoQUdyTmY0WThEYVBxUit3MU9kSWVnV244a0NvR2ZQZkdBVlc1WFhKZytPeGs2UUlhRAoyaEpvakJVcnExREFMZUNaVmV3elRWdzZCTjRER3VVZXhzYzUzYThEY1kyWWs1V0UzbGw2VUtxL1lQaVdpUE5YCjlyOEZFMk1Kd01BQkI2bVdaTHFKZWc0UkNycmlCaUNHMjZOWnhHRTdSVHRQSHlwcG9WeFdLQUZEaVd5TmRKKzMKVW5qbGRXclQ5eEZxanFmWFd3OUJoejgvRW9hR2VTU2JNSUFRRGtRUXBwMVNXcGxqcGdxdmN0WmxjNWZIaHNHNgpsbXpXNVJNNE5HOE9LdnEzVXJCaWh2Z3p3cklmb0VES3BYYmszRFhxYVNzMW84MU5INWZ0VldXYkpwL3l3TTlRCnVNQzZuMFlXaU1aTVExY0ZCeTd0dWtwTWtkK1ZQYlBraVN3QmhQa2ZaSXpVQVdkNzRuYW5ONVNLQnRjbnltZ0oKK09KY3hmWkxpVWtYUmowYVVUMUdMQTkvN3duaWtoSkkrUnZ3UmZIQmdyc3NYQktOUE9mWEdXYWp0SUFtWmMydAprUjFFOHpqQlZMSWQ3cjVNOGc1MkhLaytKK3k1ZlZnSlk5MW54RzB6Zjc4MkpqdFl1ejkra25RZDU1SkxGSkNPCmhoYnYzdVJ2aHZrcWdhdUhhZ1I1WDl2Q010Y3ZxRHNlSzdMWHJSYU9kT1VEcksvWmcvYWJpNWQrTkl5WmZFdC8KT2JGc3YzaWRBSWUvenBVNnhhMW5ZTmUzK0l4bGI2bWxabTNXQ1dHeFdlK0d2Tlcva3EzNmpaL3YvOHBZTXlWTwpwL2tKcW5mOXk0ZGJ1ZnVZQmcrUkxxRE93VTBFVWtUQXlRRVFBTnh5MnRUU2VSc3BmcnBCazkranUrS1ozemM0CnVtYUlzRWE1RHhKMnpJS0h5d1ZBUjY3VW0wSzFZUkcwNy9GNSt0RDlUSVJrZHgycGNtcGptU1F6cWRrM3pxYTkKMlp6ZWlqanoyUk55Qlk4cVlteUUwOEluY2pUc0ZGQjhPbnZkWGNzQWdqQ0ZtSTFCS25lUHhyQUJMLzJrOFgxOApheXNQYjBiZVdxUVZzaTVGc1NwQUh1Nmsxa2FMS2MrMTMweDZIZi9ZSkFqZW8rUzdIZVU1TmVPejN6RCtoNWJBClEyNXFNaVZIWDNGd0g3ckZLWnRGRm9nOU9nanppMFRrREtLeG9lRkt5QURmSWR0ZUpXRmpPbENJOUtvSWhmWHEKRXQ5Sk1ueEFwR3FzSkVsSnRmUWpJZGhNTjRMbmVwMldrdWRIQWZ3Si80MTJmZTd3aVcwcmNCTXZyL0JsQkdSWQp2TTRzVGdOMDU4RXdJdVk5UW1jOFJLNGdiQmY2R3NmR05Kaldveko1WG1YRWxta1FDQXZiUUZvQWZpNVRHZlZiCjc3UVFyaHJRbFNwZklZcnZmcHZqWW9xajYxOFNiVTZ1Qmh6aDc1OGdMbGxtTUI4TE9oeFd0cTlleW4xck1XeVIKS0wxZkVrZnZ2TWM3OHpQK1B4NnlETWE2VUllejhqWlhRODdab3U5RXJpTGJ6RjRRZklZQXFSOUxVU01uTGs2SwpvNjF0U0ZtRkVEb2JDM3RjMWprU2c0elplL3d4c2tuOTZLT2xtbnhnTUdPMHZKN0FTcnlub3hFblFFOGszV3dBCisvWUpEd2JvSVI3ekR3VHkzSnczbW4xRmduSCtjN1JiOWg5Z2VPenhLWUlOQkZ6NUhkME1LeDdrWjFVNldvYlcKS2lZWXhjQ21vRWVndVNQSEFCRUJBQUhDd1Y4RUdBRUNBQWtGQWxKRXdNa0NHd3dBQ2drUWhhdVc1dm9iNWY3ZgpGQS8vUmEraXRKRjROc0V5eWh4NHhZRE9QcTR1ajBWV1ZqTGRhYkR2RmpRdGJCTHdJeWgyYm04dU8zQVk0ci9yCnJNNVdXUThvSVhRMnZ2WHBBUU85ZzhpTmxGZXo2T0x6YmZkU0c4MEFHNzRwUXFWVlZ5Q1F4RDdGYW5CL0tHZ2UKdEFvT3N0RnhhQ0FnNG54Rmxhck1jdEZxT09YQ0ZreWxXbDUwNEpWSU92Z2JiYnlqNkk3cUNVbWJtcWF6QlNNVQpLOGMvTnorRk51MlVmL2xZV09lR29nUlNCZ1MwQ1ZCY2JtUFVwbkRITHhaV05YRFdRT0N4YmhBMVVmNThoY3l1CjAzNmtraVdIaDJPR2dKcWxvMldJcmFQWHgxY0d3MUV5K1U2ZXhidHJaZkU1a005cFp6Ukc3Wlk4M0NYcFlXTXAKa3lWWE5XbWY5SmNJV1dCclh2Sm1NaTBGRHZ0Z2czUHQxdG5veHFkaWxrNnloaWVGYzhMcUJuNkNaZ0ZVQmswdApOU2FXazNQc04wTjZVdDhWWFk2c2FpN01KMEdpaDFnRTF4YWRXajJ6Zlo5c0xHeXQyalo2d0srK1U4ODFZZVhBCnJ5YUdLSjhzSXMxODJod1FiNHFON2VpVUh6THRJaDhvVkJIbzhRNEJKU2F0ODhFNS9nT0Q2SVFJcHhjNDJpUkwKVCtvTlp3MWhkd055UE9UMUdNa2tuODZsM283a2x3bVFVV0NQbTZ2bDFhSHAzb21vK0dIQzYzUHBORk81Um5jSgpJbG8zYUJLS21vRTVsRFNNR0U4S0ZzbzVhd1RvOXo5UW5WUGtSc2s2cWVCWWl0OXhFM3gzUytpd2pjU2cwbmllCmFBa2MwTjAwbmM5VjlqZlB2dDR6LzVBNXZqSGgrTmhGd0g1aDJ2QkpWUGRzejZuT3dVMEVWSTlrZUFFUUFMM1IKb1ZzSG5jSlRtakhmQk9WNEpKc3ZDdW00RHVKRFovckRkeGF1R2NqTVVXWmFHMzM4WmVobkRxRzFZbi95czd6RQphS1lVbXF5VCtYUCtNMklBUVJUeXh3bFUxUnNEbGVtUWZXckVTZlpRQ0NtYm5GU2NMMEU3Y0J6eTR4dnRJblFlClVhRmdKWjFCbXhielFyeCtlQkJkT1REdjdSTG5OVnlnUm1Nem1rRGh4TzFJR0V1MSszRVRJZy9EeEZFN1ZRWTAKSXQvWXd6K25IdTFvNEhlbWMvR2RLeHU5aGNZdmNSVmMvWGh1ZXEvemNJTTk2bDBtK0NGYnMwSE1LQ2o4ZGdNZQpOZzZwYmJEak5NK2NWKzVCZ3BSZElwRTJsOVc3SW1wYkxpaHFjWnQ0N0o2b1d0L1JEUlZvS096UnhqaFVMVnlWCjJWUDlFU3I0OEhuYnZ4Y3B2VUFFRENRVWhzR3B1cjRFS0hGSjlBbVE0emY5MWdXTHJEYzZRbWxBQ245bzlBUlUKZk9WNWFGc1pJOW5pMU1KRUluSlRQMzdzdHovdURFQ1JpZTRMVEw0TzZQNERrdG84Uk9NMnd6WnE1Q2lSTmZuVApQUDdBUmZ4bENrcGcrZ3BMWVJseEdVdlJuNkVlWXdEdGlNUUpVUVBmcEdIU3ZUaFVsZ0RFc0RycHA0U1FTbWRBCkNCK3J2YVJxQ2F3V0tvWHMwSW4vOXd5bEdvclJVdXBlcUdDMEkwL3JoK2Y1bWF5RnZPUnp3eS80S0s0UUlFVjkKYVlUWFR2U1JsMzVNZXZmWFUxQ3VtbGFxbGU2U0RrTHIzWm5GUWdKQnFhcDBZK05tbXoySGZPL3BvaHNidEhQWAo5MlNOM2RLcWFvU0J2ek5HWTVXVDNDc3F4RHRpazM3a1IzZjkvREhwQUJFQkFBSEN3MzRFR0FFQ0FBa0ZBbFNQClpIZ0NHd0lDS1FrUWhhdVc1dm9iNWY3QlhTQUVHUUVDQUFZRkFsU1BaSGdBQ2drUVhMU3BOSHM3Q2R3ZW1BLysKS0ZvR3VGcVUwdUtUOXFibE40dWdSeWlsNWl0bVRSVmZmbDR0bTVPb1drVzh1RG51N1VlM3Z6ZHp5KzlOVjhYMgp3Ukc4MzVxalhpaldQKytBR3V4Z1c2TEI5blY1T1dpS01DSE9XblVqSlE2cE5RTUFnU042OVF6a0ZYVkYvcTVmCmJrbWE5VGdTYndqclZNeVB6TFNSd3E3SHNUM1YwMlFmcjRjeXEzOVFlSUxHeS9OSFc1ejZMWm5CeTNCYVZTZDAKbEdqQ0VjM3lmSDVPYUI3OW5hNFc4NldDVjVuNElUN2NvakZNK0xkTDZQNDZSZ21FdFdTRzMvQ0RqbkpsNkJMUgpXcWF0Uk5CV0xJTUtNcG4rWXZPT0w5VHd1UDF4YnFXcjF2WjY2d2tzbTUzTklEY1docHRwcDBLRXV6YlUwL0R0Ck9sdEJoY1g4dE9tTzM2THJTYWRYOXJ3Y2tTRVRDVllrbG1wQUhOeFBtbDAxMVlORFRodEJpZHZzaWN3MXZad1IKSHNYbit0eGxMNlJBSVJOK0ovUnczdU9pSkFxTjlRZ2VkcHgycStFMTV0OE1pVGcvRlh0QjlTeXNuc2tGVC9CSAp6MFVTTktKVVkwYnRaQnczZVhXelVuWmY1OUQ4VlcxTS85Snd6bkNIQXgwYzl3eS9nUkRpd3Q5dzRSb1hyeUpEClZBd1pnOHJ3QnlqbGRvaVRoVUpoa0NZdkowUjN4SDNrUG5QbEdYRFc0OUU5UjhDMnVtUkMzY1lPTDRVOWRPUTEKNWhTbFl5ZEY1dXJGR0NMSXZvZHRFOXE4MHVocHl0OEwvNWpqOXRid1pXdjZKTG5mQnF1WlNuQ0dxRlpSZlhsYgpKcGhrOStDQlFXd2laU1JMWlJ6cVE0ZmZsNHh5THVvbHgwMVBNYWF0a1FiUmF3LytKcGdSTmx1cktRMFBzVHJPCjh0enRPL3RwQkJqL2h1YzJER2tTd0VXdmtmV0VsUzVSTERLZG9NVnMvajVDTFlVSnpaVmlrVUpSbTdtN2IrT0EKUDNXMW5iRGh1SUQrWFYxQ1NCbUdpZlF3cG9QVHlzMjFzdFRJR0xnem5KcklmRTVtb0Z2aU9McUQvTHJjWWxzcQpDUWcweWxldTdTak9zLy84ZE0zbUMyRnlMYUUvZENaOGwyRENMaEh3MCt5bnlSQXZTSzZhR0NtWno2ak1qbVlGCk1YZ2l5N3pFU2tzTW5WRk11bElKSmhSM2VCMHd4MkdpdGlialkvWmhRN3REM2kweXk5SUxSMDdkRno0cGdrVk0KYWZ4cFZSN2Ztck1aMHQreUVOZCs5cXp5QVpzMGtzeE9Sb2MyemU5MFNDeDJqd0VYLzNLK200STBoUDJIL3c1VwpncWR2dVJMaXFmKzRCR1c0enFXa0xMbE5JZS9va3QwcjgyU3dIdEROMFVpMWFzbVpUR2o2c204U1h0d3grNWNFCjM4TXR0V3FqRGlpYlFPU3RoUlZjRVRCeVJZTThLY2pZU1VDaTRQb0JjM05wRE9Oa0ZiWm02WG9mUi9mNW1UY2wKMmpEdzZmSWVWYzRIZDFqQkdhak56RXF0bmVxcWJkQWtQUWFMc3VEMlRNa1FmVERKZkUvSWxqd2pyaERhOU1pKwpvZHRuTVdxOHZsd09aWjI0LzgvQk5LNXFYdUNZTDY3TzdBSkI0WlE2QlQrZzR6OTZpUkxidXB6dS9YSnlYa1FGCnJPWS9HaGVndm43ZkRybnQyS0M5TXBnZUZCWHpVcCtrNXJ6VWRGOGpiQ3g1YXBWakExc1dYQjlLaDNMK0RVd0YKTXZlNjk2QjV0bEh5YzFLeGpIUjZ3OUdSc2g0PQo9cE0xZwotLS0tLUVORCBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0t" } } } } ```

We don't know what this data was though, the rust project would need to keep a public archive of all data they've signed to allow auditing. If I recall correctly this would be an archive of all release-stable.toml, these then contain a sha256sum of the other artifacts, so if you have a complete view of all release-stable.toml you also have a complete view of all compilers that have been distributed.


Anyway regarding the original issue and since I looked into the keys anyway, this is the output of sq-keyring-linter:

% sq-keyring-linter --fix rust-key.pgp.ascii
Certificate 85AB96E6FA1BE5FE is not valid under the standard policy: No binding signature at time 2023-02-15T17:23:07Z
Certificate 85AB96E6FA1BE5FE contains a User ID ("Rust Language (Tag and Release Signing Key) <rust-key@rust-lang.org>") protected by SHA-1
Certificate 85AB96E6FA1BE5FE: User ID Rust Language (Tag and Release Signing Key) <rust-key@rust-lang.org>: Failed to update binding signature: Invalid argument: No secret key
Certificate 85AB96E6FA1BE5FE, key 5CB4A9347B3B09DC uses a SHA-1-protected binding signature.
Certificate 85AB96E6FA1BE5FE, key 5CB4A9347B3B09DC: Failed to update binding signature: Invalid argument: No secret key
Certificate 85AB96E6FA1BE5FE, key 8E9AA3F7AB3F5826 uses a SHA-1-protected binding signature.
Certificate 85AB96E6FA1BE5FE, key 8E9AA3F7AB3F5826: Failed to update binding signature: Invalid argument: No secret key
Examined 1 certificate.
  0 certificates are invalid and were not linted. (GOOD)
  1 certificate was linted.
  1 of the 1 certificates (100%) has at least one issue. (BAD)
0 of the linted certificates were revoked.
  0 of the 0 certificates has revocation certificates that are weaker than the certificate and should be recreated. (GOOD)
0 of the linted certificates were expired.
1 of the non-revoked linted certificate has at least one non-revoked User ID:
  1 has at least one User ID protected by SHA-1. (BAD)
  1 has all User IDs protected by SHA-1. (BAD)
1 of the non-revoked linted certificates has at least one non-revoked, live subkey:
  1 has at least one non-revoked, live subkey with a binding signature that uses SHA-1. (BAD)
0 of the non-revoked linted certificates have at least one non-revoked, live, signing-capable subkey:
  0 certificates have at least one non-revoked, live, signing-capable subkey with a strong binding signature, but a backsig that uses SHA-1. (GOOD)
Failed to fix 3 issues. (BAD)

Basically the primary key 108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE self-certifies the uid Rust Language (Tag and Release Signing Key) <rust-key@rust-lang.org> and both subkeys belong to 108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE but it does so with sha1:

``` % sq packet dump rust-key.pgp.ascii Public-Key Packet, old CTB, 525 bytes Version: 4 Creation time: 2013-09-26 23:18:33 UTC Pk algo: RSA Pk size: 4096 bits Fingerprint: 108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE KeyID: 85AB96E6FA1BE5FE User ID Packet, old CTB, 68 bytes Value: Rust Language (Tag and Release Signing Key) Signature Packet, old CTB, 568 bytes Version: 4 Type: PositiveCertification Pk algo: RSA Hash algo: SHA1 Hashed area: Signature creation time: 2013-09-26 23:18:33 UTC Key flags: CS Symmetric algo preferences: AES256, AES192, AES128, CAST5, TripleDES Hash preferences: SHA256, SHA1, SHA384, SHA512, SHA224 Compression preferences: Zlib, BZip2, Zip Features: MDC Keyserver preferences: no modify Unhashed area: Issuer: 85AB96E6FA1BE5FE Digest prefix: 5F61 Level: 0 (signature over data) Public-Subkey Packet, old CTB, 525 bytes Version: 4 Creation time: 2013-09-26 23:18:33 UTC Pk algo: RSA Pk size: 4096 bits Fingerprint: 29D57CE15D76E78CD57D326A8E9AA3F7AB3F5826 KeyID: 8E9AA3F7AB3F5826 Signature Packet, old CTB, 543 bytes Version: 4 Type: SubkeyBinding Pk algo: RSA Hash algo: SHA1 Hashed area: Signature creation time: 2013-09-26 23:18:33 UTC Key flags: EtEr Unhashed area: Issuer: 85AB96E6FA1BE5FE Digest prefix: DF14 Level: 0 (signature over data) Public-Subkey Packet, old CTB, 525 bytes Version: 4 Creation time: 2014-12-15 22:45:12 UTC Pk algo: RSA Pk size: 4096 bits Fingerprint: C13466B7E169A085188632165CB4A9347B3B09DC KeyID: 5CB4A9347B3B09DC Signature Packet, old CTB, 1086 bytes Version: 4 Type: SubkeyBinding Pk algo: RSA Hash algo: SHA1 Hashed area: Signature creation time: 2014-12-15 22:45:12 UTC Key flags: S Unhashed area: Issuer: 85AB96E6FA1BE5FE Embedded signature: Signature Packet Version: 4 Type: PrimaryKeyBinding Pk algo: RSA Hash algo: SHA1 Hashed area: Signature creation time: 2014-12-15 22:45:12 UTC Unhashed area: Issuer: 5CB4A9347B3B09DC Digest prefix: 1E98 Level: 0 (signature over data) Digest prefix: D16B Level: 0 (signature over data) ```

To fix this with sequoia, use:

$ apt-get install sq-keyring-linter
$ gpg --export-secret-keys rust-key@rust-lang.org | sq-keyring-linter --fix | gpg --import

gpg is going to ask for as password to protect the secret key, but sq-keyring-linter is going to immediately ask for the password again to issue new sha2 signatures for the uid paket and both subkeys, so it doesn't really matter what you set there.

I've tried to find instructions on how to fix the key with gpg natively but it seems very involved (https://old.nixaid.com/gpg-migration-sha1-to-sha2/). It also doesn't explain how to get rid of the subkey signatures and suggests to revoke them and generate new ones (?!).

Cross-referecing the release scripts, this should work:

(
for x in  "op://tnuk54f56audltg5e7if776ieq/67bxwduvibdkpio7psx53preka/56b6j26lmvelpn6jeecsr5fsxi" "op://tnuk54f56audltg5e7if776ieq/q6ztr2lrorg3fa3mzg6kx26bnm/m6tnrye775cefbekajhawec3ja" "op://tnuk54f56audltg5e7if776ieq/fnzoe3nw7rck7ezqhwpkj7j2xe/kjzmpsermnc4bovkwslhjd34se"; do
op read "$x"
done
) | sq-keyring-linter --fix -p "$(op read op://tnuk54f56audltg5e7if776ieq/pks4bn2wf4r7plue24cdqsw4ga/password)" | gpg --import

# in rustup codebase

gpg --armor --export rust-key@rust-lang.org > src/rust-key.pgp.ascii

If you just want to go with a new key and you want to go with gpg again, put this in your ~/.gnupg/gpg.conf first:

personal-cipher-preferences AES256
personal-digest-preferences SHA512
cert-digest-algo SHA512
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed

Sorry this reply got so long, if anything is unclear please just let me know.

rbtcollins commented 1 year ago

I had assumed we'd update the embedde certificate in rustup via new rustup release rather than sideloading keys. We need to do that in some form of expand-contract so that rustup's self-update continues to work across the transition.

kpcyrd commented 1 year ago

I reverse engineered the rustup self-update recently and the pgp signatures aren't fully in use yet.

rustup fetches this url: https://static.rust-lang.org/rustup/release-stable.toml

schema-version = '1'
version = '1.25.2'

If this version is less recent than rustup's own version (say 1.25.1) it's going to fetch and execute the elf file from this url next: https://static.rust-lang.org/rustup/archive/1.25.2/x86_64-unknown-linux-musl/rustup-init.

Security is provided by https and pgp signatures aren't mandatory yet, so rolling out the update shouldn't cause issues.

I have unit-tests for rustup here: https://github.com/kpcyrd/sh4d0wup/blob/main/contrib/plot-rustup.yaml

pietroalbini commented 1 year ago

Let's not bikeshed a key rotation mechanism in this thread, but let's focus on removing the SHA1 signatures from the existing key. Key rotation (and in general enforcing signatures) would require a larger design effort, and I know it's one of the priorities of the foundation security engineer.