Generalize make_errors.go to allow EVP covering multiple directories.

In doing so, this switches make_errors.go to take library names as
parameters rather than detecting it from the CWD. (I considered
detecting it, but then we'd need to map evp -> crypto/whatever and
crypto/whatever -> evp in both directions.)

Since crypto/hpke currently sits in the EVP namespace, I've gone ahead
and added that, so it should be easier to define new errors in
crypto/hpke. I've not added crypto/cipher, etc., yet. Moving those will
be a breaking change (consumers that put ERR_LIB_CIPHER and ERR_LIB_EVP
in a switch/case need patches).

Bug: 398
Change-Id: Ibae2afd46e076891fa517c377b540b2e492516f0
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/46264
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/hpke/hpke.c b/crypto/hpke/hpke.c
index ee03e53..d3e9c7c 100644
--- a/crypto/hpke/hpke.c
+++ b/crypto/hpke/hpke.c
@@ -19,7 +19,7 @@
 #include <openssl/bytestring.h>
 #include <openssl/digest.h>
 #include <openssl/err.h>
-#include <openssl/evp.h>
+#include <openssl/evp_errors.h>
 #include <openssl/hkdf.h>
 #include <openssl/sha.h>
 
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 0710792..bdbcc2d 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -59,6 +59,7 @@
 
 #include <openssl/base.h>
 
+#include <openssl/evp_errors.h>
 #include <openssl/thread.h>
 
 // OpenSSL included digest and cipher functions in this header so we include
@@ -1091,42 +1092,4 @@
 
 #endif
 
-#define EVP_R_BUFFER_TOO_SMALL 100
-#define EVP_R_COMMAND_NOT_SUPPORTED 101
-#define EVP_R_DECODE_ERROR 102
-#define EVP_R_DIFFERENT_KEY_TYPES 103
-#define EVP_R_DIFFERENT_PARAMETERS 104
-#define EVP_R_ENCODE_ERROR 105
-#define EVP_R_EXPECTING_AN_EC_KEY_KEY 106
-#define EVP_R_EXPECTING_AN_RSA_KEY 107
-#define EVP_R_EXPECTING_A_DSA_KEY 108
-#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 109
-#define EVP_R_INVALID_DIGEST_LENGTH 110
-#define EVP_R_INVALID_DIGEST_TYPE 111
-#define EVP_R_INVALID_KEYBITS 112
-#define EVP_R_INVALID_MGF1_MD 113
-#define EVP_R_INVALID_OPERATION 114
-#define EVP_R_INVALID_PADDING_MODE 115
-#define EVP_R_INVALID_PSS_SALTLEN 116
-#define EVP_R_KEYS_NOT_SET 117
-#define EVP_R_MISSING_PARAMETERS 118
-#define EVP_R_NO_DEFAULT_DIGEST 119
-#define EVP_R_NO_KEY_SET 120
-#define EVP_R_NO_MDC2_SUPPORT 121
-#define EVP_R_NO_NID_FOR_CURVE 122
-#define EVP_R_NO_OPERATION_SET 123
-#define EVP_R_NO_PARAMETERS_SET 124
-#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 125
-#define EVP_R_OPERATON_NOT_INITIALIZED 126
-#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 127
-#define EVP_R_UNSUPPORTED_ALGORITHM 128
-#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 129
-#define EVP_R_NOT_A_PRIVATE_KEY 130
-#define EVP_R_INVALID_SIGNATURE 131
-#define EVP_R_MEMORY_LIMIT_EXCEEDED 132
-#define EVP_R_INVALID_PARAMETERS 133
-#define EVP_R_INVALID_PEER_KEY 134
-#define EVP_R_NOT_XOF_OR_INVALID_LENGTH 135
-#define EVP_R_EMPTY_PSK 136
-
 #endif  // OPENSSL_HEADER_EVP_H
diff --git a/include/openssl/evp_errors.h b/include/openssl/evp_errors.h
new file mode 100644
index 0000000..2482584
--- /dev/null
+++ b/include/openssl/evp_errors.h
@@ -0,0 +1,98 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_EVP_ERRORS_H
+#define OPENSSL_HEADER_EVP_ERRORS_H
+
+#define EVP_R_BUFFER_TOO_SMALL 100
+#define EVP_R_COMMAND_NOT_SUPPORTED 101
+#define EVP_R_DECODE_ERROR 102
+#define EVP_R_DIFFERENT_KEY_TYPES 103
+#define EVP_R_DIFFERENT_PARAMETERS 104
+#define EVP_R_ENCODE_ERROR 105
+#define EVP_R_EXPECTING_AN_EC_KEY_KEY 106
+#define EVP_R_EXPECTING_AN_RSA_KEY 107
+#define EVP_R_EXPECTING_A_DSA_KEY 108
+#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 109
+#define EVP_R_INVALID_DIGEST_LENGTH 110
+#define EVP_R_INVALID_DIGEST_TYPE 111
+#define EVP_R_INVALID_KEYBITS 112
+#define EVP_R_INVALID_MGF1_MD 113
+#define EVP_R_INVALID_OPERATION 114
+#define EVP_R_INVALID_PADDING_MODE 115
+#define EVP_R_INVALID_PSS_SALTLEN 116
+#define EVP_R_KEYS_NOT_SET 117
+#define EVP_R_MISSING_PARAMETERS 118
+#define EVP_R_NO_DEFAULT_DIGEST 119
+#define EVP_R_NO_KEY_SET 120
+#define EVP_R_NO_MDC2_SUPPORT 121
+#define EVP_R_NO_NID_FOR_CURVE 122
+#define EVP_R_NO_OPERATION_SET 123
+#define EVP_R_NO_PARAMETERS_SET 124
+#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 125
+#define EVP_R_OPERATON_NOT_INITIALIZED 126
+#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 127
+#define EVP_R_UNSUPPORTED_ALGORITHM 128
+#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 129
+#define EVP_R_NOT_A_PRIVATE_KEY 130
+#define EVP_R_INVALID_SIGNATURE 131
+#define EVP_R_MEMORY_LIMIT_EXCEEDED 132
+#define EVP_R_INVALID_PARAMETERS 133
+#define EVP_R_INVALID_PEER_KEY 134
+#define EVP_R_NOT_XOF_OR_INVALID_LENGTH 135
+#define EVP_R_EMPTY_PSK 136
+
+#endif  // OPENSSL_HEADER_EVP_ERRORS_H
diff --git a/util/make_errors.go b/util/make_errors.go
index 2525a69..4e2718b 100644
--- a/util/make_errors.go
+++ b/util/make_errors.go
@@ -34,19 +34,41 @@
 
 var resetFlag *bool = flag.Bool("reset", false, "If true, ignore current assignments and reassign from scratch")
 
-func makeErrors(reset bool) error {
+type libraryInfo struct {
+	sourceDirs []string
+	headerName string
+}
+
+func getLibraryInfo(lib string) libraryInfo {
+	var info libraryInfo
+	if lib == "ssl" {
+		info.sourceDirs = []string{"ssl"}
+	} else {
+		info.sourceDirs = []string{
+			filepath.Join("crypto", lib),
+			filepath.Join("crypto", lib+"_extra"),
+			filepath.Join("crypto", "fipsmodule", lib),
+		}
+	}
+	info.headerName = lib + ".h"
+
+	if lib == "evp" {
+		info.headerName = "evp_errors.h"
+		info.sourceDirs = append(info.sourceDirs, filepath.Join("crypto", "hpke"))
+	}
+
+	return info
+}
+
+func makeErrors(lib string, reset bool) error {
 	topLevelPath, err := findToplevel()
 	if err != nil {
 		return err
 	}
 
-	dirName, err := os.Getwd()
-	if err != nil {
-		return err
-	}
+	info := getLibraryInfo(lib)
 
-	lib := filepath.Base(dirName)
-	headerPath := filepath.Join(topLevelPath, "include", "openssl", lib+".h")
+	headerPath := filepath.Join(topLevelPath, "include", "openssl", info.headerName)
 	errDir := filepath.Join(topLevelPath, "crypto", "err")
 	dataPath := filepath.Join(errDir, lib+".errordata")
 
@@ -79,43 +101,30 @@
 		return err
 	}
 
-	dir, err := os.Open(".")
-	if err != nil {
-		return err
-	}
-	defer dir.Close()
-
-	filenames, err := dir.Readdirnames(-1)
-	if err != nil {
-		return err
-	}
-
-	if filepath.Base(filepath.Dir(dirName)) == "fipsmodule" {
-		// Search the non-FIPS half of library for error codes as well.
-		extraPath := filepath.Join(topLevelPath, "crypto", lib+"_extra")
-		extraDir, err := os.Open(extraPath)
-		if err != nil && !os.IsNotExist(err) {
+	for _, sourceDir := range info.sourceDirs {
+		fullPath := filepath.Join(topLevelPath, sourceDir)
+		dir, err := os.Open(fullPath)
+		if err != nil {
+			if os.IsNotExist(err) {
+				// Some directories in the search path may not exist.
+				continue
+			}
 			return err
 		}
-		if err == nil {
-			defer extraDir.Close()
-			extraFilenames, err := extraDir.Readdirnames(-1)
-			if err != nil {
+		defer dir.Close()
+		filenames, err := dir.Readdirnames(-1)
+		if err != nil {
+			return err
+		}
+
+		for _, name := range filenames {
+			if !strings.HasSuffix(name, ".c") && !strings.HasSuffix(name, ".cc") {
+				continue
+			}
+
+			if err := addReasons(reasons, filepath.Join(fullPath, name), prefix); err != nil {
 				return err
 			}
-			for _, extraFilename := range extraFilenames {
-				filenames = append(filenames, filepath.Join(extraPath, extraFilename))
-			}
-		}
-	}
-
-	for _, name := range filenames {
-		if !strings.HasSuffix(name, ".c") && !strings.HasSuffix(name, ".cc") {
-			continue
-		}
-
-		if err := addReasons(reasons, name, prefix); err != nil {
-			return err
 		}
 	}
 
@@ -155,12 +164,16 @@
 }
 
 func findToplevel() (path string, err error) {
-	path = ".."
+	path = "."
 	buildingPath := filepath.Join(path, "BUILDING.md")
 
 	_, err = os.Stat(buildingPath)
 	for i := 0; i < 2 && err != nil && os.IsNotExist(err); i++ {
-		path = filepath.Join("..", path)
+		if i == 0 {
+			path = ".."
+		} else {
+			path = filepath.Join("..", path)
+		}
 		buildingPath = filepath.Join(path, "BUILDING.md")
 		_, err = os.Stat(buildingPath)
 	}
@@ -404,9 +417,15 @@
 
 func main() {
 	flag.Parse()
-
-	if err := makeErrors(*resetFlag); err != nil {
-		fmt.Fprintf(os.Stderr, "%s\n", err)
+	if flag.NArg() == 0 {
+		fmt.Fprintf(os.Stderr, "Usage: make_errors.go LIB [LIB2...]\n")
 		os.Exit(1)
 	}
+
+	for _, lib := range flag.Args() {
+		if err := makeErrors(lib, *resetFlag); err != nil {
+			fmt.Fprintf(os.Stderr, "Error generating errors for %q: %s\n", lib, err)
+			os.Exit(1)
+		}
+	}
 }