Index: /trunk/src/VBox/Runtime/tools/RTEfiSigDb.cpp
===================================================================
--- /trunk/src/VBox/Runtime/tools/RTEfiSigDb.cpp	(revision 90315)
+++ /trunk/src/VBox/Runtime/tools/RTEfiSigDb.cpp	(revision 90316)
@@ -41,4 +41,5 @@
 #include <iprt/stream.h>
 #include <iprt/string.h>
+#include <iprt/uuid.h>
 #include <iprt/vfs.h>
 
@@ -52,4 +53,15 @@
 *   Global Variables                                                                                                             *
 *********************************************************************************************************************************/
+/** Signature type identifier to internal type mapping. */
+struct
+{
+    const char   *pszId;
+    RTEFISIGTYPE enmType;
+} g_aId2SigType[] =
+{
+    { "sha256",  RTEFISIGTYPE_SHA256  },
+    { "rsa2048", RTEFISIGTYPE_RSA2048 },
+    { "x509",    RTEFISIGTYPE_X509    }
+};
 
 
@@ -83,5 +95,56 @@
                  , RTPathFilename(pszArg0));
 
+    if (!pszCommand || !strcmp(pszCommand, "add"))
+        RTPrintf("Usage: %s add <signature database path> <x509|sha256|rsa2048> <owner uuid> <signature path> ...\n"
+                 , RTPathFilename(pszArg0));
+
     return RTEXITCODE_SUCCESS;
+}
+
+
+static RTEFISIGTYPE rtEfiSigDbGetTypeById(const char *pszId)
+{
+    for (uint32_t i = 0; i < RT_ELEMENTS(g_aId2SigType); i++)
+        if (!strcmp(pszId, g_aId2SigType[i].pszId))
+            return g_aId2SigType[i].enmType;
+
+    return RTEFISIGTYPE_INVALID;
+}
+
+
+/**
+ * Opens the specified signature database, returning an VFS file handle on success.
+ *
+ * @returns IPRT status code.
+ * @param   pszPath             Path to the signature database.
+ * @param   phVfsFile           Where to return the VFS file handle on success.
+ */
+static int rtEfiSigDbOpen(const char *pszPath, PRTVFSFILE phVfsFile)
+{
+    int rc;
+
+    if (RTVfsChainIsSpec(pszPath))
+    {
+        RTVFSOBJ hVfsObj;
+        rc = RTVfsChainOpenObj(pszPath, RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
+                               RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING | RTPATH_F_ON_LINK,
+                               &hVfsObj, NULL, NULL);
+        if (   RT_SUCCESS(rc)
+            && RTVfsObjGetType(hVfsObj) == RTVFSOBJTYPE_FILE)
+        {
+            *phVfsFile = RTVfsObjToFile(hVfsObj);
+            RTVfsObjRelease(hVfsObj);
+        }
+        else
+        {
+            RTPrintf("'%s' doesn't point to a file\n", pszPath);
+            rc = VERR_INVALID_PARAMETER;
+        }
+    }
+    else
+        rc = RTVfsFileOpenNormal(pszPath, RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
+                                 phVfsFile);
+
+    return rc;
 }
 
@@ -117,32 +180,5 @@
     RT_NOREF(pszArg0);
 
-    /*
-     * Parse arguments.
-     */
-    static const RTGETOPTDEF s_aOptions[] =
-    {
-        { "--input",    'i', RTGETOPT_REQ_STRING }
-    };
-
-    int             rc       = VINF_SUCCESS;
-    RTEXITCODE      rcExit   = RTEXITCODE_SUCCESS;
-    const char     *pszInput = NULL;
-
-    RTGETOPTUNION   ValueUnion;
-    RTGETOPTSTATE   GetState;
-    RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
-    while ((rc = RTGetOpt(&GetState, &ValueUnion)))
-    {
-        switch (rc)
-        {
-            case 'i':
-                pszInput = ValueUnion.psz;
-                break;
-            default:
-                return RTGetOptPrintError(rc, &ValueUnion);
-        }
-    }
-
-    if (!pszInput)
+    if (!cArgs)
     {
         RTPrintf("An input path must be given\n");
@@ -150,41 +186,157 @@
     }
 
+    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     RTVFSFILE hVfsFile = NIL_RTVFSFILE;
-    if (RTVfsChainIsSpec(pszInput))
-    {
-        RTVFSOBJ hVfsObj;
-        rc = RTVfsChainOpenObj(pszInput, RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
-                               RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING | RTPATH_F_ON_LINK,
-                               &hVfsObj, NULL, NULL);
-        if (   RT_SUCCESS(rc)
-            && RTVfsObjGetType(hVfsObj) == RTVFSOBJTYPE_FILE)
-        {
-            hVfsFile = RTVfsObjToFile(hVfsObj);
-            RTVfsObjRelease(hVfsObj);
+    int rc = rtEfiSigDbOpen(papszArgs[0], &hVfsFile);
+    if (RT_SUCCESS(rc))
+    {
+        RTEFISIGDB hEfiSigDb;
+        rc = RTEfiSigDbCreate(&hEfiSigDb);
+        if (RT_SUCCESS(rc))
+        {
+            uint32_t idxSig = 0;
+
+            rc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFile);
+            if (RT_SUCCESS(rc))
+                RTEfiSigDbEnum(hEfiSigDb, rtEfiSgDbEnum, &idxSig);
+            else
+            {
+                RTPrintf("Loading the signature database failed with %Rrc\n", rc);
+                rcExit = RTEXITCODE_FAILURE;
+            }
+
+            RTEfiSigDbDestroy(hEfiSigDb);
         }
         else
         {
-            RTPrintf("'%s' doesn't point to a file\n", pszInput);
-            return RTEXITCODE_FAILURE;
-        }
+            RTPrintf("Creating the signature database failed with %Rrc\n", rc);
+            rcExit = RTEXITCODE_FAILURE;
+        }
+
+        RTVfsFileRelease(hVfsFile);
     }
     else
-        rc = RTVfsFileOpenNormal(pszInput, RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
-                                 &hVfsFile);
-
-    RTEFISIGDB hEfiSigDb;
-    rc = RTEfiSigDbCreate(&hEfiSigDb);
+        rcExit = RTEXITCODE_FAILURE;
+
+    return rcExit;
+}
+
+
+/**
+ * Handles the 'add' command.
+ *
+ * @returns Program exit code.
+ * @param   pszArg0             The program name.
+ * @param   cArgs               The number of arguments to the 'add' command.
+ * @param   papszArgs           The argument vector, starting after 'add'.
+ */
+static RTEXITCODE rtEfiSgDbCmdAdd(const char *pszArg0, int cArgs, char **papszArgs)
+{
+    RT_NOREF(pszArg0);
+
+    if (!cArgs)
+    {
+        RTPrintf("The signature database path is missing\n");
+        return RTEXITCODE_FAILURE;
+    }
+
+    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+    RTVFSFILE hVfsFile = NIL_RTVFSFILE;
+    int rc = rtEfiSigDbOpen(papszArgs[0], &hVfsFile);
     if (RT_SUCCESS(rc))
     {
-        uint32_t idxSig = 0;
-
-        rc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFile);
+        RTEFISIGDB hEfiSigDb;
+        rc = RTEfiSigDbCreate(&hEfiSigDb);
         if (RT_SUCCESS(rc))
-            RTEfiSigDbEnum(hEfiSigDb, rtEfiSgDbEnum, &idxSig);
-
-        RTEfiSigDbDestroy(hEfiSigDb);
-    }
-
-    RTVfsFileRelease(hVfsFile);
+        {
+            uint64_t cbSigDb = 0;
+            rc = RTVfsFileQuerySize(hVfsFile, &cbSigDb);
+            if (   RT_SUCCESS(rc)
+                && cbSigDb)
+                rc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFile);
+            if (RT_SUCCESS(rc))
+            {
+                cArgs--;
+                papszArgs++;
+
+                while (cArgs >= 3)
+                {
+                    RTEFISIGTYPE enmSigType    = rtEfiSigDbGetTypeById(papszArgs[0]);
+                    const char *pszUuidOwner   = papszArgs[1];
+                    const char *pszSigDataPath = papszArgs[2];
+
+                    if (enmSigType == RTEFISIGTYPE_INVALID)
+                    {
+                        RTPrintf("Signature type '%s' is not known\n", papszArgs[0]);
+                        break;
+                    }
+
+                    RTUUID UuidOwner;
+                    rc = RTUuidFromStr(&UuidOwner, pszUuidOwner);
+                    if (RT_FAILURE(rc))
+                    {
+                        RTPrintf("UUID '%s' is malformed\n", pszUuidOwner);
+                        break;
+                    }
+
+                    RTVFSFILE hVfsFileSigData = NIL_RTVFSFILE;
+                    rc = rtEfiSigDbOpen(pszSigDataPath, &hVfsFileSigData);
+                    if (RT_FAILURE(rc))
+                    {
+                        RTPrintf("Opening '%s' failed with %Rrc\n", pszSigDataPath);
+                        break;
+                    }
+
+                    rc = RTEfiSigDbAddSignatureFromFile(hEfiSigDb, enmSigType, &UuidOwner, hVfsFileSigData);
+                    RTVfsFileRelease(hVfsFileSigData);
+                    if (RT_FAILURE(rc))
+                    {
+                        RTPrintf("Adding signature data from '%s' failed with %Rrc\n", pszSigDataPath, rc);
+                        break;
+                    }
+                    papszArgs += 3;
+                    cArgs     -= 3;
+                }
+
+                if (RT_SUCCESS(rc))
+                {
+                    if (!cArgs)
+                    {
+                        rc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
+                        AssertRC(rc);
+
+                        rc = RTEfiSigDbWriteToFile(hEfiSigDb, hVfsFile);
+                        if (RT_FAILURE(rc))
+                        {
+                            RTPrintf("Writing the updated signature database failed with %Rrc\n", rc);
+                            rcExit = RTEXITCODE_FAILURE;
+                        }
+                    }
+                    else
+                    {
+                        RTPrintf("Incomplete list of entries to add given\n");
+                        rcExit = RTEXITCODE_FAILURE;
+                    }
+                }
+            }
+            else
+            {
+                RTPrintf("Loading the signature database failed with %Rrc\n", rc);
+                rcExit = RTEXITCODE_FAILURE;
+            }
+
+            RTEfiSigDbDestroy(hEfiSigDb);
+        }
+        else
+        {
+            RTPrintf("Creating the signature database failed with %Rrc\n", rc);
+            rcExit = RTEXITCODE_FAILURE;
+        }
+
+        RTVfsFileRelease(hVfsFile);
+    }
+    else
+        rcExit = RTEXITCODE_FAILURE;
+
     return rcExit;
 }
@@ -205,4 +357,6 @@
     else if (!strcmp(argv[1], "list"))
         rcExit = rtEfiSgDbCmdList(argv[0], argc - 2, argv + 2);
+    else if (!strcmp(argv[1], "add"))
+        rcExit = rtEfiSgDbCmdAdd(argv[0], argc - 2, argv + 2);
     else if (   !strcmp(argv[1], "-h")
              || !strcmp(argv[1], "-?")
