package dns
import (
"bufio"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"io"
"math/big"
"strconv"
"strings"
)
func (k *DNSKEY ) NewPrivateKey (s string ) (crypto .PrivateKey , error ) {
if s == "" || s [len (s )-1 ] != '\n' {
return k .ReadPrivateKey (strings .NewReader (s +"\n" ), "" )
}
return k .ReadPrivateKey (strings .NewReader (s ), "" )
}
func (k *DNSKEY ) ReadPrivateKey (q io .Reader , file string ) (crypto .PrivateKey , error ) {
m , err := parseKey (q , file )
if m == nil {
return nil , err
}
if _ , ok := m ["private-key-format" ]; !ok {
return nil , ErrPrivKey
}
if m ["private-key-format" ] != "v1.2" && m ["private-key-format" ] != "v1.3" {
return nil , ErrPrivKey
}
algoStr , _ , _ := strings .Cut (m ["algorithm" ], " " )
algo , err := strconv .ParseUint (algoStr , 10 , 8 )
if err != nil {
return nil , ErrPrivKey
}
switch uint8 (algo ) {
case RSASHA1 , RSASHA1NSEC3SHA1 , RSASHA256 , RSASHA512 :
priv , err := readPrivateKeyRSA (m )
if err != nil {
return nil , err
}
pub := k .publicKeyRSA ()
if pub == nil {
return nil , ErrKey
}
priv .PublicKey = *pub
return priv , nil
case ECDSAP256SHA256 , ECDSAP384SHA384 :
priv , err := readPrivateKeyECDSA (m )
if err != nil {
return nil , err
}
pub := k .publicKeyECDSA ()
if pub == nil {
return nil , ErrKey
}
priv .PublicKey = *pub
return priv , nil
case ED25519 :
return readPrivateKeyED25519 (m )
default :
return nil , ErrAlg
}
}
func readPrivateKeyRSA(m map [string ]string ) (*rsa .PrivateKey , error ) {
p := new (rsa .PrivateKey )
p .Primes = []*big .Int {nil , nil }
for k , v := range m {
switch k {
case "modulus" , "publicexponent" , "privateexponent" , "prime1" , "prime2" :
v1 , err := fromBase64 ([]byte (v ))
if err != nil {
return nil , err
}
switch k {
case "modulus" :
p .PublicKey .N = new (big .Int ).SetBytes (v1 )
case "publicexponent" :
i := new (big .Int ).SetBytes (v1 )
p .PublicKey .E = int (i .Int64 ())
case "privateexponent" :
p .D = new (big .Int ).SetBytes (v1 )
case "prime1" :
p .Primes [0 ] = new (big .Int ).SetBytes (v1 )
case "prime2" :
p .Primes [1 ] = new (big .Int ).SetBytes (v1 )
}
case "exponent1" , "exponent2" , "coefficient" :
case "created" , "publish" , "activate" :
}
}
return p , nil
}
func readPrivateKeyECDSA(m map [string ]string ) (*ecdsa .PrivateKey , error ) {
p := new (ecdsa .PrivateKey )
p .D = new (big .Int )
for k , v := range m {
switch k {
case "privatekey" :
v1 , err := fromBase64 ([]byte (v ))
if err != nil {
return nil , err
}
p .D .SetBytes (v1 )
case "created" , "publish" , "activate" :
}
}
return p , nil
}
func readPrivateKeyED25519(m map [string ]string ) (ed25519 .PrivateKey , error ) {
var p ed25519 .PrivateKey
for k , v := range m {
switch k {
case "privatekey" :
p1 , err := fromBase64 ([]byte (v ))
if err != nil {
return nil , err
}
if len (p1 ) != ed25519 .SeedSize {
return nil , ErrPrivKey
}
p = ed25519 .NewKeyFromSeed (p1 )
case "created" , "publish" , "activate" :
}
}
return p , nil
}
func parseKey(r io .Reader , file string ) (map [string ]string , error ) {
m := make (map [string ]string )
var k string
c := newKLexer (r )
for l , ok := c .Next (); ok ; l , ok = c .Next () {
switch l .value {
case zKey :
k = l .token
case zValue :
if k == "" {
return nil , &ParseError {file : file , err : "no private key seen" , lex : l }
}
m [strings .ToLower (k )] = l .token
k = ""
}
}
if err := c .Err (); err != nil {
return nil , &ParseError {file : file , err : err .Error()}
}
return m , nil
}
type klexer struct {
br io .ByteReader
readErr error
line int
column int
key bool
eol bool
}
func newKLexer(r io .Reader ) *klexer {
br , ok := r .(io .ByteReader )
if !ok {
br = bufio .NewReaderSize (r , 1024 )
}
return &klexer {
br : br ,
line : 1 ,
key : true ,
}
}
func (kl *klexer ) Err () error {
if kl .readErr == io .EOF {
return nil
}
return kl .readErr
}
func (kl *klexer ) readByte () (byte , bool ) {
if kl .readErr != nil {
return 0 , false
}
c , err := kl .br .ReadByte ()
if err != nil {
kl .readErr = err
return 0 , false
}
if kl .eol {
kl .line ++
kl .column = 0
kl .eol = false
}
if c == '\n' {
kl .eol = true
} else {
kl .column ++
}
return c , true
}
func (kl *klexer ) Next () (lex , bool ) {
var (
l lex
str strings .Builder
commt bool
)
for x , ok := kl .readByte (); ok ; x , ok = kl .readByte () {
l .line , l .column = kl .line , kl .column
switch x {
case ':' :
if commt || !kl .key {
break
}
kl .key = false
kl .readByte ()
l .value = zKey
l .token = str .String ()
return l , true
case ';' :
commt = true
case '\n' :
if commt {
commt = false
}
if kl .key && str .Len () == 0 {
break
}
kl .key = true
l .value = zValue
l .token = str .String ()
return l , true
default :
if commt {
break
}
str .WriteByte (x )
}
}
if kl .readErr != nil && kl .readErr != io .EOF {
return lex {value : zEOF }, false
}
if str .Len () > 0 {
l .value = zValue
l .token = str .String ()
return l , true
}
return lex {value : zEOF }, false
}
The pages are generated with Golds v0.8.2 . (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 .