@@ -12,18 +12,21 @@ import (
1212 "crypto/ed25519"
1313 "crypto/elliptic"
1414 "crypto/rand"
15+ "crypto/rsa"
1516 "crypto/sha256"
1617 "crypto/tls"
1718 "crypto/x509"
1819 "crypto/x509/pkix"
1920 "encoding/asn1"
2021 "encoding/base64"
22+ "encoding/binary"
2123 "encoding/pem"
2224 "errors"
25+ "fmt"
2326 "io"
27+ "math"
2428 "math/big"
2529 "strconv"
26- "strings"
2730 "time"
2831)
2932
@@ -45,27 +48,34 @@ type PrivateKey interface {
4548
4649// ParsePrivateKey parses s and returns it as PrivateKey.
4750//
48- // Currently, ParsePrivateKey either returns a *EdDSAPrivateKey,
49- // a *ECDSAPrivateKey or an error.
51+ // Currently, ParsePrivateKey either returns a [ *EdDSAPrivateKey] ,
52+ // a [ *ECDSAPrivateKey], a [*RSAPrivateKey] or an error.
5053func ParsePrivateKey (s string ) (PrivateKey , error ) {
51- switch {
52- default :
53- return nil , errors .New ("mtls: invalid private key" )
54-
55- case strings .HasPrefix (s , "k1:" ):
56- var key EdDSAPrivateKey
57- if err := key .UnmarshalText ([]byte (s )); err != nil {
58- return nil , err
54+ if len (s ) >= 3 {
55+ switch s [:3 ] {
56+ case "k1:" :
57+ var key EdDSAPrivateKey
58+ if err := key .UnmarshalText ([]byte (s )); err != nil {
59+ return nil , err
60+ }
61+ return & key , nil
62+
63+ case "k2:" :
64+ var key ECDSAPrivateKey
65+ if err := key .UnmarshalText ([]byte (s )); err != nil {
66+ return nil , err
67+ }
68+ return & key , nil
69+
70+ case "k3:" :
71+ var key RSAPrivateKey
72+ if err := key .UnmarshalText ([]byte (s )); err != nil {
73+ return nil , err
74+ }
75+ return & key , nil
5976 }
60- return & key , nil
61-
62- case strings .HasPrefix (s , "k2:" ):
63- var key ECDSAPrivateKey
64- if err := key .UnmarshalText ([]byte (s )); err != nil {
65- return nil , err
66- }
67- return & key , nil
6877 }
78+ return nil , errors .New ("mtls: invalid private key" )
6979}
7080
7181// EdDSAPrivateKey is a [PrivateKey] for the EdDSA signature algorithm
@@ -210,7 +220,7 @@ func (pk *ECDSAPrivateKey) Private() crypto.PrivateKey {
210220 }
211221}
212222
213- // Private returns the ECDSA public key.
223+ // Public returns the ECDSA public key.
214224func (pk * ECDSAPrivateKey ) Public () crypto.PublicKey {
215225 var X , Y big.Int
216226 return & ecdsa.PublicKey {
@@ -223,9 +233,9 @@ func (pk *ECDSAPrivateKey) Public() crypto.PublicKey {
223233// Identity returns the identity of the ECDSA public key.
224234func (pk * ECDSAPrivateKey ) Identity () Identity { return pk .identity }
225235
226- // MarshalText returns a textual representation of the private key.
236+ // MarshalText returns a textual representation of the ECDSA private key.
227237//
228- // It returns output equivalent to [ECDSAPrivateKey.String]
238+ // It returns output equivalent to [ECDSAPrivateKey.String].
229239func (pk * ECDSAPrivateKey ) MarshalText () ([]byte , error ) {
230240 // We use FillBytes instead of Bytes since the later returns
231241 // a variable-size slice. However, we want all private key
@@ -241,7 +251,7 @@ func (pk *ECDSAPrivateKey) MarshalText() ([]byte, error) {
241251 return b , nil
242252}
243253
244- // UnmarshalText parses an private key textual representation.
254+ // UnmarshalText parses a ECDSA private key textual representation.
245255func (pk * ECDSAPrivateKey ) UnmarshalText (text []byte ) error {
246256 if ! bytes .HasPrefix (text , []byte ("k2:" )) {
247257 return errors .New ("mtls: invalid ECDSA private key" )
@@ -313,9 +323,166 @@ func (pk *ECDSAPrivateKey) String() string {
313323 return "k2:" + base64 .RawURLEncoding .EncodeToString (priv )
314324}
315325
326+ // GenerateKey generates a random RSA private key of the given bit size.
327+ //
328+ // If bits is less than 1024, [GenerateKeyRSA] returns an error. See the
329+ // "[Minimum key size]" section for further details.
330+ //
331+ // Most applications should use [crypto/rand.Reader] as random. Note that the
332+ // returned key does not depend deterministically on the bytes read from rand,
333+ // and may change between calls and/or between versions.
334+ //
335+ // [Minimum key size]: https://pkg.go.dev/crypto/rsa#hdr-Minimum_key_size
336+ func GenerateKeyRSA (random io.Reader , bits int ) (* RSAPrivateKey , error ) {
337+ priv , err := rsa .GenerateKey (random , bits )
338+ if err != nil {
339+ return nil , err
340+ }
341+ if priv .E > math .MaxUint32 {
342+ return nil , errors .New ("mtls: public RSA exponent " + strconv .Itoa (priv .E ) + " is too large" )
343+ }
344+ priv .Precompute ()
345+
346+ identity , err := rsaIdentity (priv )
347+ if err != nil {
348+ return nil , err
349+ }
350+ return & RSAPrivateKey {
351+ priv : priv ,
352+ identity : identity ,
353+ }, nil
354+ }
355+
356+ // RSAPrivateKey represents an RSA [PrivateKey].
357+ type RSAPrivateKey struct {
358+ priv * rsa.PrivateKey
359+ identity Identity
360+ }
361+
362+ // Private returns the RSA private key.
363+ func (pk * RSAPrivateKey ) Private () crypto.PrivateKey { return pk .priv }
364+
365+ // Public returns the RSA public key.
366+ func (pk * RSAPrivateKey ) Public () crypto.PublicKey { return pk .priv .Public () }
367+
368+ // Identity returns the identity of the RSA public key.
369+ func (pk * RSAPrivateKey ) Identity () Identity { return pk .identity }
370+
371+ // MarshalText returns a textual representation of the private key.
372+ //
373+ // It returns output equivalent to [RSAPrivateKey.String].
374+ func (pk * RSAPrivateKey ) MarshalText () ([]byte , error ) {
375+ return base64 .RawURLEncoding .AppendEncode ([]byte ("k3:" ), pk .encode ()), nil
376+ }
377+
378+ // UnmarshalText parses a textual representation of an RSA private key.
379+ func (pk * RSAPrivateKey ) UnmarshalText (text []byte ) error {
380+ if ! bytes .HasPrefix (text , []byte ("k3:" )) {
381+ return errors .New ("mtls: invalid RSA private key" )
382+ }
383+ text = text [3 :]
384+
385+ var err error
386+ data := make ([]byte , 0 , base64 .RawURLEncoding .DecodedLen (len (text )))
387+ if data , err = base64 .RawURLEncoding .AppendDecode (data , text ); err != nil {
388+ return err
389+ }
390+
391+ var E uint32
392+ if len (data ) < 6 {
393+ return errors .New ("mtls: invalid RSA private key parameter E" )
394+ }
395+ if n := binary .BigEndian .Uint16 (data ); n != 4 {
396+ return errors .New ("mtls: invalid RSA private key parameter E: invalid encoding length " + strconv .Itoa (int (n )))
397+ }
398+ E = binary .BigEndian .Uint32 (data [2 :])
399+ data = data [6 :]
400+
401+ var P , Q , D * big.Int
402+ if data , P , err = decodeRSAParam (data ); err != nil {
403+ return fmt .Errorf ("mtls: invalid RSA private key parameter P: %w" , err )
404+ }
405+ if data , Q , err = decodeRSAParam (data ); err != nil {
406+ return fmt .Errorf ("mtls: invalid RSA private key parameter Q: %w" , err )
407+ }
408+ if data , D , err = decodeRSAParam (data ); err != nil {
409+ return fmt .Errorf ("mtls: invalid RSA private key parameter D: %w" , err )
410+ }
411+ if len (data ) != 0 {
412+ return errors .New ("mtls: invalid RSA private key: private key contains additional data" )
413+ }
414+
415+ priv := & rsa.PrivateKey {
416+ PublicKey : rsa.PublicKey {
417+ N : new (big.Int ).Mul (P , Q ),
418+ E : int (E ),
419+ },
420+ D : D ,
421+ Primes : []* big.Int {P , Q },
422+ }
423+ priv .Precompute ()
424+ if err = priv .Validate (); err != nil {
425+ return fmt .Errorf ("mtls: invalid RSA private key: %w" , err )
426+ }
427+
428+ identity , err := rsaIdentity (priv )
429+ if err != nil {
430+ return err
431+ }
432+
433+ pk .priv = priv
434+ pk .identity = identity
435+ return nil
436+ }
437+
438+ // String returns a string representation of the private key.
439+ //
440+ // Its output is equivalent to [RSAPrivateKey.MarshalText]
441+ func (pk * RSAPrivateKey ) String () string {
442+ return "k3:" + base64 .RawURLEncoding .EncodeToString (pk .encode ())
443+ }
444+
445+ // encode returns the RSA key's binary representation:
446+ //
447+ // len(E) | E | len(P) | P | len(Q) | Q | len(D) | D
448+ //
449+ // All numbers are represented in big endian.
450+ //
451+ // Values that can be re-computed are omitted to be space efficient.
452+ // For example, the modulus N = PQ. The private exponent D can also
453+ // be re-computed given P and Q as D = E⁻¹ mod φ(N) where φ(N) = (p-1)(q-1).
454+ //
455+ // However, FIPS 186-5 requires computing it as E⁻¹ mod λ(N) where λ(N) = lcm(p-1, q-1).
456+ // Hence, we include D to avoid re-implementing private exponent calculations.
457+ // The binary representation puts D at the end such that we can support shorter
458+ // private keys (without D) in the future.
459+ func (pk * RSAPrivateKey ) encode () []byte {
460+ var (
461+ D , P , Q = pk .priv .D , pk .priv .Primes [0 ], pk .priv .Primes [1 ]
462+ d , p , q = (D .BitLen () + 7 ) / 8 , (P .BitLen () + 7 ) / 8 , (Q .BitLen () + 7 ) / 8
463+
464+ buf = make ([]byte , max (d , p , q ))
465+ out = make ([]byte , 0 , 12 + d + p + q ) // length-prefixed encoded len: 2 + 4 + 2 + d + 2 + p + 2 + q
466+ )
467+
468+ out = binary .BigEndian .AppendUint16 (out , 4 )
469+ out = binary .BigEndian .AppendUint32 (out , uint32 (pk .priv .E ))
470+
471+ out = binary .BigEndian .AppendUint16 (out , uint16 (p ))
472+ out = append (out , P .FillBytes (buf [:p ])... )
473+
474+ out = binary .BigEndian .AppendUint16 (out , uint16 (q ))
475+ out = append (out , Q .FillBytes (buf [:q ])... )
476+
477+ out = binary .BigEndian .AppendUint16 (out , uint16 (d ))
478+ out = append (out , D .FillBytes (buf [:d ])... )
479+ return out
480+ }
481+
316482var (
317483 oidPublicKeyEdDSA = asn1.ObjectIdentifier {1 , 3 , 101 , 112 }
318484 oidPublicKeyECDSA = asn1.ObjectIdentifier {1 , 2 , 840 , 10045 , 2 , 1 }
485+ oidPublicKeyRSA = asn1.ObjectIdentifier {1 , 2 , 840 , 113549 , 1 , 1 , 1 }
319486
320487 oidNamedCurveP256 = asn1.ObjectIdentifier {1 , 2 , 840 , 10045 , 3 , 1 , 7 }
321488 oidNamedCurveP384 = asn1.ObjectIdentifier {1 , 3 , 132 , 0 , 34 }
@@ -384,7 +551,53 @@ func ecdsaIdentity(key *ecdsa.PrivateKey) (Identity, error) {
384551 }, nil
385552}
386553
387- // NewCertificate returns a new TLS certificate using the
554+ func rsaIdentity (key * rsa.PrivateKey ) (Identity , error ) {
555+ type PKCS1 struct {
556+ N * big.Int
557+ E int
558+ }
559+ pubKey , err := asn1 .Marshal (PKCS1 {
560+ N : key .PublicKey .N ,
561+ E : key .PublicKey .E ,
562+ })
563+ if err != nil {
564+ return Identity {}, fmt .Errorf ("mtls: failed to encode RSA public key: %w" , err )
565+ }
566+ b , err := asn1 .Marshal (publicKeyInfo {
567+ Algorithm : pkix.AlgorithmIdentifier {
568+ Algorithm : oidPublicKeyRSA ,
569+ Parameters : asn1 .NullRawValue ,
570+ },
571+ PublicKey : asn1.BitString {BitLength : len (pubKey ) * 8 , Bytes : pubKey },
572+ })
573+ if err != nil {
574+ return Identity {}, fmt .Errorf ("mtls: failed to encode RSA public key: %w" , err )
575+ }
576+
577+ return Identity {
578+ hash : sha256 .Sum256 (b ),
579+ }, nil
580+ }
581+
582+ // decodeRSAParam decodes a length-encoded big endian binary
583+ // representation of an RSA private key parameter. In particular,
584+ // the private exponent D and the prime factors P and Q.
585+ func decodeRSAParam (b []byte ) ([]byte , * big.Int , error ) {
586+ if len (b ) < 2 {
587+ return nil , nil , errors .New ("invalid length encoding" )
588+ }
589+
590+ n := binary .BigEndian .Uint16 (b )
591+ if n == 0 {
592+ return nil , nil , errors .New ("parameter length is zero" )
593+ }
594+ if int (n ) > len (b )- 2 {
595+ return nil , nil , errors .New ("parameter length " + strconv .Itoa (int (n )) + " exceeds data" )
596+ }
597+ return b [2 + n :], new (big.Int ).SetBytes (b [2 : 2 + n ]), nil
598+ }
599+
600+ // newCertificate returns a new TLS certificate using the
388601// given private key.
389602func newCertificate (key PrivateKey ) (* tls.Certificate , error ) {
390603 serialNumberLimit := new (big.Int ).Lsh (big .NewInt (1 ), 128 )
0 commit comments