package main import ( "encoding/base64" "encoding/json" "encoding/pem" "fmt" "log" "net/http" "os" "strings" ) type CTLogRootsResponse struct { Certificates []string `json:"certificates"` } func generateRoots(args []string) { sourceURL := "https://rennet2027h2.log.ct.ipng.ch/" outputFile := "roots.pem" // Parse command line arguments for i := 0; i < len(args); i++ { switch args[i] { case "--source": if i+1 >= len(args) { log.Fatal("--source flag requires a URL argument") } sourceURL = args[i+1] i++ // Skip the next argument since we used it case "--output": if i+1 >= len(args) { log.Fatal("--output flag requires a filename argument") } outputFile = args[i+1] i++ // Skip the next argument since we used it default: log.Fatalf("Unknown argument: %s", args[i]) } } // Ensure source URL ends with / if !strings.HasSuffix(sourceURL, "/") { sourceURL += "/" } // Construct the get-roots URL getRootsURL := sourceURL + "ct/v1/get-roots" // Fetch roots from CT log fmt.Printf("Fetching roots from: %s\n", getRootsURL) resp, err := http.Get(getRootsURL) if err != nil { log.Fatalf("Failed to fetch roots: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { log.Fatalf("HTTP request failed with status: %d", resp.StatusCode) } // Parse JSON response var rootsResp CTLogRootsResponse err = json.NewDecoder(resp.Body).Decode(&rootsResp) if err != nil { log.Fatalf("Failed to parse JSON response: %v", err) } // Create output file outFile, err := os.Create(outputFile) if err != nil { log.Fatalf("Failed to create output file %s: %v", outputFile, err) } defer outFile.Close() // Write each certificate as PEM for _, certBase64 := range rootsResp.Certificates { // Decode base64 certificate certBytes, err := base64.StdEncoding.DecodeString(certBase64) if err != nil { log.Fatalf("Failed to decode certificate: %v", err) } // Create PEM block pemBlock := &pem.Block{ Type: "CERTIFICATE", Bytes: certBytes, } // Write PEM to file err = pem.Encode(outFile, pemBlock) if err != nil { log.Fatalf("Failed to write PEM certificate: %v", err) } } fmt.Printf("Successfully wrote %d certificates to %s\n", len(rootsResp.Certificates), outputFile) }