1package cmd 2 3import ( 4 "crypto/x509" 5 "encoding/pem" 6 "fmt" 7 "os" 8 "strings" 9 "time" 10 11 "github.com/go-acme/lego/v4/certcrypto" 12 "github.com/go-acme/lego/v4/lego" 13 "github.com/go-acme/lego/v4/log" 14 "github.com/go-acme/lego/v4/registration" 15 "github.com/urfave/cli" 16) 17 18const filePerm os.FileMode = 0o600 19 20func setup(ctx *cli.Context, accountsStorage *AccountsStorage) (*Account, *lego.Client) { 21 keyType := getKeyType(ctx) 22 privateKey := accountsStorage.GetPrivateKey(keyType) 23 24 var account *Account 25 if accountsStorage.ExistsAccountFilePath() { 26 account = accountsStorage.LoadAccount(privateKey) 27 } else { 28 account = &Account{Email: accountsStorage.GetUserID(), key: privateKey} 29 } 30 31 client := newClient(ctx, account, keyType) 32 33 return account, client 34} 35 36func newClient(ctx *cli.Context, acc registration.User, keyType certcrypto.KeyType) *lego.Client { 37 config := lego.NewConfig(acc) 38 config.CADirURL = ctx.GlobalString("server") 39 40 config.Certificate = lego.CertificateConfig{ 41 KeyType: keyType, 42 Timeout: time.Duration(ctx.GlobalInt("cert.timeout")) * time.Second, 43 } 44 config.UserAgent = fmt.Sprintf("lego-cli/%s", ctx.App.Version) 45 46 if ctx.GlobalIsSet("http-timeout") { 47 config.HTTPClient.Timeout = time.Duration(ctx.GlobalInt("http-timeout")) * time.Second 48 } 49 50 client, err := lego.NewClient(config) 51 if err != nil { 52 log.Fatalf("Could not create client: %v", err) 53 } 54 55 if client.GetExternalAccountRequired() && !ctx.GlobalIsSet("eab") { 56 log.Fatal("Server requires External Account Binding. Use --eab with --kid and --hmac.") 57 } 58 59 return client 60} 61 62// getKeyType the type from which private keys should be generated. 63func getKeyType(ctx *cli.Context) certcrypto.KeyType { 64 keyType := ctx.GlobalString("key-type") 65 switch strings.ToUpper(keyType) { 66 case "RSA2048": 67 return certcrypto.RSA2048 68 case "RSA4096": 69 return certcrypto.RSA4096 70 case "RSA8192": 71 return certcrypto.RSA8192 72 case "EC256": 73 return certcrypto.EC256 74 case "EC384": 75 return certcrypto.EC384 76 } 77 78 log.Fatalf("Unsupported KeyType: %s", keyType) 79 return "" 80} 81 82func getEmail(ctx *cli.Context) string { 83 email := ctx.GlobalString("email") 84 if email == "" { 85 log.Fatal("You have to pass an account (email address) to the program using --email or -m") 86 } 87 return email 88} 89 90func createNonExistingFolder(path string) error { 91 if _, err := os.Stat(path); os.IsNotExist(err) { 92 return os.MkdirAll(path, 0o700) 93 } else if err != nil { 94 return err 95 } 96 return nil 97} 98 99func readCSRFile(filename string) (*x509.CertificateRequest, error) { 100 bytes, err := os.ReadFile(filename) 101 if err != nil { 102 return nil, err 103 } 104 raw := bytes 105 106 // see if we can find a PEM-encoded CSR 107 var p *pem.Block 108 rest := bytes 109 for { 110 // decode a PEM block 111 p, rest = pem.Decode(rest) 112 113 // did we fail? 114 if p == nil { 115 break 116 } 117 118 // did we get a CSR? 119 if p.Type == "CERTIFICATE REQUEST" || p.Type == "NEW CERTIFICATE REQUEST" { 120 raw = p.Bytes 121 } 122 } 123 124 // no PEM-encoded CSR 125 // assume we were given a DER-encoded ASN.1 CSR 126 // (if this assumption is wrong, parsing these bytes will fail) 127 return x509.ParseCertificateRequest(raw) 128} 129