55package main
66
77import (
8+ "bytes"
89 "log"
910 "os"
1011 "os/exec"
@@ -83,8 +84,8 @@ func (m *mkcert) checkNSS() bool {
8384func (m * mkcert ) installNSS () bool {
8485 if m .forEachNSSProfile (func (profile string ) {
8586 cmd := exec .Command (certutilPath , "-A" , "-d" , profile , "-t" , "C,," , "-n" , m .caUniqueName (), "-i" , filepath .Join (m .CAROOT , rootName ))
86- out , err := cmd . CombinedOutput ( )
87- fatalIfCmdErr (err , "certutil -A" , out )
87+ out , err := execCertutil ( cmd )
88+ fatalIfCmdErr (err , "certutil -A -d " + profile , out )
8889 }) == 0 {
8990 log .Printf ("ERROR: no %s security databases found" , NSSBrowsers )
9091 return false
@@ -104,11 +105,24 @@ func (m *mkcert) uninstallNSS() {
104105 return
105106 }
106107 cmd := exec .Command (certutilPath , "-D" , "-d" , profile , "-n" , m .caUniqueName ())
107- out , err := cmd . CombinedOutput ( )
108- fatalIfCmdErr (err , "certutil -D" , out )
108+ out , err := execCertutil ( cmd )
109+ fatalIfCmdErr (err , "certutil -D -d " + profile , out )
109110 })
110111}
111112
113+ // execCertutil will execute a "certutil" command and if needed re-execute
114+ // the command with commandWithSudo to work around file permissions.
115+ func execCertutil (cmd * exec.Cmd ) ([]byte , error ) {
116+ out , err := cmd .CombinedOutput ()
117+ if err != nil && bytes .Contains (out , []byte ("SEC_ERROR_READ_ONLY" )) && runtime .GOOS != "windows" {
118+ origArgs := cmd .Args [1 :]
119+ cmd = commandWithSudo (cmd .Path )
120+ cmd .Args = append (cmd .Args , origArgs ... )
121+ out , err = cmd .CombinedOutput ()
122+ }
123+ return out , err
124+ }
125+
112126func (m * mkcert ) forEachNSSProfile (f func (profile string )) (found int ) {
113127 profiles , _ := filepath .Glob (FirefoxProfile )
114128 profiles = append (profiles , nssDBs ... )
0 commit comments