package x509
import (
"crypto/rsa"
"encoding/asn1"
"errors"
"math/big"
)
type pkcs1PrivateKey struct {
Version int
N *big .Int
E int
D *big .Int
P *big .Int
Q *big .Int
Dp *big .Int `asn1:"optional"`
Dq *big .Int `asn1:"optional"`
Qinv *big .Int `asn1:"optional"`
AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"`
}
type pkcs1AdditionalRSAPrime struct {
Prime *big .Int
Exp *big .Int
Coeff *big .Int
}
type pkcs1PublicKey struct {
N *big .Int
E int
}
func ParsePKCS1PrivateKey (der []byte ) (*rsa .PrivateKey , error ) {
var priv pkcs1PrivateKey
rest , err := asn1 .Unmarshal (der , &priv )
if len (rest ) > 0 {
return nil , asn1 .SyntaxError {Msg : "trailing data" }
}
if err != nil {
if _ , err := asn1 .Unmarshal (der , &ecPrivateKey {}); err == nil {
return nil , errors .New ("x509: failed to parse private key (use ParseECPrivateKey instead for this key format)" )
}
if _ , err := asn1 .Unmarshal (der , &pkcs8 {}); err == nil {
return nil , errors .New ("x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)" )
}
return nil , err
}
if priv .Version > 1 {
return nil , errors .New ("x509: unsupported private key version" )
}
if priv .N .Sign () <= 0 || priv .D .Sign () <= 0 || priv .P .Sign () <= 0 || priv .Q .Sign () <= 0 {
return nil , errors .New ("x509: private key contains zero or negative value" )
}
key := new (rsa .PrivateKey )
key .PublicKey = rsa .PublicKey {
E : priv .E ,
N : priv .N ,
}
key .D = priv .D
key .Primes = make ([]*big .Int , 2 +len (priv .AdditionalPrimes ))
key .Primes [0 ] = priv .P
key .Primes [1 ] = priv .Q
for i , a := range priv .AdditionalPrimes {
if a .Prime .Sign () <= 0 {
return nil , errors .New ("x509: private key contains zero or negative prime" )
}
key .Primes [i +2 ] = a .Prime
}
err = key .Validate ()
if err != nil {
return nil , err
}
key .Precompute ()
return key , nil
}
func MarshalPKCS1PrivateKey (key *rsa .PrivateKey ) []byte {
key .Precompute ()
version := 0
if len (key .Primes ) > 2 {
version = 1
}
priv := pkcs1PrivateKey {
Version : version ,
N : key .N ,
E : key .PublicKey .E ,
D : key .D ,
P : key .Primes [0 ],
Q : key .Primes [1 ],
Dp : key .Precomputed .Dp ,
Dq : key .Precomputed .Dq ,
Qinv : key .Precomputed .Qinv ,
}
priv .AdditionalPrimes = make ([]pkcs1AdditionalRSAPrime , len (key .Precomputed .CRTValues ))
for i , values := range key .Precomputed .CRTValues {
priv .AdditionalPrimes [i ].Prime = key .Primes [2 +i ]
priv .AdditionalPrimes [i ].Exp = values .Exp
priv .AdditionalPrimes [i ].Coeff = values .Coeff
}
b , _ := asn1 .Marshal (priv )
return b
}
func ParsePKCS1PublicKey (der []byte ) (*rsa .PublicKey , error ) {
var pub pkcs1PublicKey
rest , err := asn1 .Unmarshal (der , &pub )
if err != nil {
if _ , err := asn1 .Unmarshal (der , &publicKeyInfo {}); err == nil {
return nil , errors .New ("x509: failed to parse public key (use ParsePKIXPublicKey instead for this key format)" )
}
return nil , err
}
if len (rest ) > 0 {
return nil , asn1 .SyntaxError {Msg : "trailing data" }
}
if pub .N .Sign () <= 0 || pub .E <= 0 {
return nil , errors .New ("x509: public key contains zero or negative value" )
}
if pub .E > 1 <<31 -1 {
return nil , errors .New ("x509: public key contains large public exponent" )
}
return &rsa .PublicKey {
E : pub .E ,
N : pub .N ,
}, nil
}
func MarshalPKCS1PublicKey (key *rsa .PublicKey ) []byte {
derBytes , _ := asn1 .Marshal (pkcs1PublicKey {
N : key .N ,
E : key .E ,
})
return derBytes
}
The pages are generated with Golds v0.7.0-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .