Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add ability to extract RSA public key parameters #16

Merged
merged 3 commits into from
Feb 20, 2023

Conversation

cpswan
Copy link
Member

@cpswan cpswan commented Feb 20, 2023

Ongoing work for atsign-foundation/micropython#2 requires the ability to extract integers from another atSign's public key.

- What I did

Tidied up the work done by @duanqi211 to add Bit String support to uasn1.py

Added a method to extract public key integers.

- How I did it

Getting the parameters from a public key is very similar to doing the same with a private key, except that they're encoded into a Bit String rather than an Octet String.

One trip hazard encountered is the spurious null byte at the beginning of the sequence extracted from the bit string, which throws off the ASN.1 parser if it's not trimmed out. @realvarx @TylerTrott @JeremyTubongbanua @XavierChanth any thoughts on how/why this is happening would be appreciated?

- How to verify it

Running micropython locally on WSL2:

import sys
sys.path.append('./lib')
from pem_service import get_pem_parameters, get_pub_parameters, get_pem_key
pubpem='MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArm6AMIrw+2lAPvXVNulIcjabLbhDIynXIMIwjoLGOHKgjvuALW9gySiIDBUG54wtsD15etVL9NSGVchjAoZi7H3NAKQCyn1UNaKzL7Bxnqdm+GyX1OtAQTTFEcqzQZmQDrhTNRs2W2GNaQ+NXEIETfeBxD/VNsumIrzUCybJfRGHcYj5XCcku7YvdluiO+VhQHH1mdGuKuunONo2czNa/0Ir27rWo1SB43jMfbzR/duUT3xD3tB2y+NdWSozbe4dnrCTip4yJ2gdqXwThfK8l2wr/QB/NcLhWcAEo9kQDboOKsS91f3ba7zcBao7Z0lfY/yF2i+dCXB0QA2mmzE6QQIDAQAB'
print(get_pub_parameters(pubpem))

Example output:

[22019955010203162012544509859681164488930880432261972458899838175754293611805217089916406940112100721734274388147856483780254109148070008367596231568313961662789496989123745899284270182818488572671086203864082243948488737628459929294695956520594608527748960101978987192974848362310384109216948438946485471834986032338428092083698086017140393675485856360534183839432285060596258898230833036180671422861642200309962484563154992547400750879332457266064473574420436143142612640028499344486953806118226974258478244812723412044668846945795043769351304074262759431478803683125647954039718875283087402759554272630345833724481, 65537]

- Description for the changelog

feat: Add ability to extract RSA public key parameters

@realvarx
Copy link
Collaborator

realvarx commented Feb 20, 2023

Got a possible answer for the "spurious null byte" @cpswan . Take a look at this, and also at this.

Looking at the DER scheme:
image

We can see that the BIT STRING field has "4+271" bytes. But that "4" isn't taking in account one zero byte at the end of the encapsulation that we see before the 271 bytes which contain the integers that we need.

It isn't being taken in account because it doesn't belong to the encapsulation, but to the content of BIT STRING (that's why the asn1 decoder includes it):

image
271 + 1 = 272 (multiple of 8)
272/8 = 34 (which is a natural, non-decimal number)

That prepended zero byte means the number of zeroes padded at the end of the bit string in order to be a multiple of 8, including the prepended byte itself (so in this case the bit string has not been padded with zeroes (unused values) at the end).

An example of a public key with a BIT STRING with some zeroes padding would be useful. The thing is that I have tried with 3 different atSigns and I always get no padding. Maybe some keys created by some generation systems or with formats don't necessarily have to deal with paddings because they are intended to have a certain length (if that's true, it makes our task easier).

(Images are from ASN.1 JavaScript decoder, although I used a different key on them)

@cpswan
Copy link
Member Author

cpswan commented Feb 20, 2023

Thanks @realvarx

I think in that case we should be handling stripping the zero in the uasn1 library.

Public keys are always going to be 2048 bits (==256 bytes) so I don't expect zero padding will ever come into play, which can leave us all scratching out heads why they chose to encode as a bit string rather than an octet string?

I'm going to make this a draft while I refactor.

@cpswan cpswan marked this pull request as draft February 20, 2023 17:58
@realvarx
Copy link
Collaborator

which can leave us all scratching out heads why they chose to encode as a bit string rather than an octet string?

I also found this comment in one of the links that I shared:

Public keys are always BIT STRING in X.509; this is an historical remnant from older times, kept for the sake of backward compatibility. – Thomas Pornin

@JeremyTubongbanua
Copy link
Member

I was able to get the n and e parameters from a base64 encoded public rsa key here:

def get_public_n_e(publicRsaKeyDecrypted: str):

@cpswan cpswan marked this pull request as ready for review February 20, 2023 18:26
@cpswan
Copy link
Member Author

cpswan commented Feb 20, 2023

Thanks @JeremyTubongbanua looks like we arrived at much the same approach.

This is ready for review again.

Copy link
Collaborator

@realvarx realvarx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested and working fine on Pico W

@cpswan cpswan merged commit 00b7225 into trunk Feb 20, 2023
@cpswan cpswan deleted the cpswan-pubkey-params branch February 20, 2023 19:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants