diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## Changes in 0.38.1
+  - Add support for `extra-files` (see #603)
+  - Preserve empty lines in `description` when `cabal-version >= 3` (see #612)
+
 ## Changes in 0.38.0
   - Generate `build-tool-depends` instead of `build-tools` starting with
     `cabal-version: 2` (fixes #596)
diff --git a/hpack.cabal b/hpack.cabal
--- a/hpack.cabal
+++ b/hpack.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           hpack
-version:        0.38.0
+version:        0.38.1
 synopsis:       A modern format for Haskell packages
 description:    See README at <https://github.com/sol/hpack#readme>
 category:       Development
@@ -25,33 +25,6 @@
   location: https://github.com/sol/hpack
 
 library
-  hs-source-dirs:
-      src
-  ghc-options: -Wall -fno-warn-incomplete-uni-patterns
-  build-depends:
-      Cabal >=3.0.0.0 && <3.13
-    , Glob >=0.9.0
-    , aeson >=1.4.3.0
-    , base >=4.13 && <5
-    , bifunctors
-    , bytestring
-    , containers
-    , crypton
-    , deepseq
-    , directory >=1.2.5.0
-    , filepath
-    , http-client
-    , http-client-tls >=0.3.6.2
-    , http-types
-    , infer-license >=0.2.0 && <0.3
-    , mtl
-    , pretty
-    , scientific
-    , text
-    , transformers
-    , unordered-containers
-    , vector
-    , yaml >=0.10.0
   exposed-modules:
       Hpack
       Hpack.Config
@@ -86,18 +59,11 @@
       Paths_hpack
   autogen-modules:
       Paths_hpack
-  default-language: Haskell2010
-  if impl(ghc >= 9.4.5) && os(windows)
-    build-depends:
-        network >=3.1.2.9
-
-executable hpack
-  main-is: Main.hs
   hs-source-dirs:
-      driver
+      src
   ghc-options: -Wall -fno-warn-incomplete-uni-patterns
   build-depends:
-      Cabal >=3.0.0.0 && <3.13
+      Cabal >=3.0.0.0 && <3.15
     , Glob >=0.9.0
     , aeson >=1.4.3.0
     , base >=4.13 && <5
@@ -108,7 +74,6 @@
     , deepseq
     , directory >=1.2.5.0
     , filepath
-    , hpack
     , http-client
     , http-client-tls >=0.3.6.2
     , http-types
@@ -126,19 +91,14 @@
     build-depends:
         network >=3.1.2.9
 
-test-suite spec
-  type: exitcode-stdio-1.0
-  main-is: Spec.hs
+executable hpack
+  main-is: Main.hs
   hs-source-dirs:
-      test
-      src
+      driver
   ghc-options: -Wall -fno-warn-incomplete-uni-patterns
-  cpp-options: -DTEST
   build-depends:
-      Cabal >=3.0.0.0 && <3.13
+      Cabal >=3.0.0.0 && <3.15
     , Glob >=0.9.0
-    , HUnit >=1.6.0.0
-    , QuickCheck
     , aeson >=1.4.3.0
     , base >=4.13 && <5
     , bifunctors
@@ -148,25 +108,27 @@
     , deepseq
     , directory >=1.2.5.0
     , filepath
-    , hspec ==2.*
+    , hpack
     , http-client
     , http-client-tls >=0.3.6.2
     , http-types
     , infer-license >=0.2.0 && <0.3
-    , interpolate
-    , mockery >=0.3
     , mtl
     , pretty
     , scientific
-    , template-haskell
-    , temporary
     , text
     , transformers
     , unordered-containers
     , vector
     , yaml >=0.10.0
-  build-tool-depends:
-      hspec-discover:hspec-discover
+  default-language: Haskell2010
+  if impl(ghc >= 9.4.5) && os(windows)
+    build-depends:
+        network >=3.1.2.9
+
+test-suite spec
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
   other-modules:
       Data.Aeson.Config.FromValueSpec
       Data.Aeson.Config.TypesSpec
@@ -190,6 +152,7 @@
       Hpack.Utf8Spec
       Hpack.UtilSpec
       HpackSpec
+      SpecHook
       Data.Aeson.Config.FromValue
       Data.Aeson.Config.Key
       Data.Aeson.Config.KeyMap
@@ -222,6 +185,45 @@
       Paths_hpack
   autogen-modules:
       Paths_hpack
+  hs-source-dirs:
+      test
+      src
+  ghc-options: -Wall -fno-warn-incomplete-uni-patterns
+  cpp-options: -DTEST
+  build-tool-depends:
+      hspec-discover:hspec-discover
+  build-depends:
+      Cabal >=3.0.0.0 && <3.15
+    , Glob >=0.9.0
+    , HUnit >=1.6.0.0
+    , QuickCheck
+    , aeson >=1.4.3.0
+    , base >=4.13 && <5
+    , bifunctors
+    , bytestring
+    , containers
+    , crypton
+    , deepseq
+    , directory >=1.2.5.0
+    , filepath
+    , hspec ==2.*
+    , http-client
+    , http-client-tls >=0.3.6.2
+    , http-types
+    , infer-license >=0.2.0 && <0.3
+    , interpolate
+    , mockery >=0.3
+    , mtl
+    , pretty
+    , scientific
+    , template-haskell
+    , temporary
+    , text
+    , transformers
+    , unordered-containers
+    , vcr
+    , vector
+    , yaml >=0.10.0
   default-language: Haskell2010
   if impl(ghc >= 9.4.5) && os(windows)
     build-depends:
diff --git a/resources/test/hpack.cabal b/resources/test/hpack.cabal
--- a/resources/test/hpack.cabal
+++ b/resources/test/hpack.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           hpack
-version:        0.38.0
+version:        0.38.1
 synopsis:       A modern format for Haskell packages
 description:    See README at <https://github.com/sol/hpack#readme>
 category:       Development
@@ -25,33 +25,6 @@
   location: https://github.com/sol/hpack
 
 library
-  hs-source-dirs:
-      src
-  ghc-options: -Wall -fno-warn-incomplete-uni-patterns
-  build-depends:
-      Cabal >=3.0.0.0 && <3.13
-    , Glob >=0.9.0
-    , aeson >=1.4.3.0
-    , base >=4.13 && <5
-    , bifunctors
-    , bytestring
-    , containers
-    , crypton
-    , deepseq
-    , directory >=1.2.5.0
-    , filepath
-    , http-client
-    , http-client-tls >=0.3.6.2
-    , http-types
-    , infer-license >=0.2.0 && <0.3
-    , mtl
-    , pretty
-    , scientific
-    , text
-    , transformers
-    , unordered-containers
-    , vector
-    , yaml >=0.10.0
   exposed-modules:
       Hpack
       Hpack.Config
@@ -86,18 +59,11 @@
       Paths_hpack
   autogen-modules:
       Paths_hpack
-  default-language: Haskell2010
-  if impl(ghc >= 9.4.5) && os(windows)
-    build-depends:
-        network >=3.1.2.9
-
-executable hpack
-  main-is: Main.hs
   hs-source-dirs:
-      driver
+      src
   ghc-options: -Wall -fno-warn-incomplete-uni-patterns
   build-depends:
-      Cabal >=3.0.0.0 && <3.13
+      Cabal >=3.0.0.0 && <3.15
     , Glob >=0.9.0
     , aeson >=1.4.3.0
     , base >=4.13 && <5
@@ -108,7 +74,6 @@
     , deepseq
     , directory >=1.2.5.0
     , filepath
-    , hpack
     , http-client
     , http-client-tls >=0.3.6.2
     , http-types
@@ -126,19 +91,14 @@
     build-depends:
         network >=3.1.2.9
 
-test-suite spec
-  type: exitcode-stdio-1.0
-  main-is: Spec.hs
+executable hpack
+  main-is: Main.hs
   hs-source-dirs:
-      test
-      src
+      driver
   ghc-options: -Wall -fno-warn-incomplete-uni-patterns
-  cpp-options: -DTEST
   build-depends:
-      Cabal >=3.0.0.0 && <3.13
+      Cabal >=3.0.0.0 && <3.15
     , Glob >=0.9.0
-    , HUnit >=1.6.0.0
-    , QuickCheck
     , aeson >=1.4.3.0
     , base >=4.13 && <5
     , bifunctors
@@ -148,25 +108,27 @@
     , deepseq
     , directory >=1.2.5.0
     , filepath
-    , hspec ==2.*
+    , hpack
     , http-client
     , http-client-tls >=0.3.6.2
     , http-types
     , infer-license >=0.2.0 && <0.3
-    , interpolate
-    , mockery >=0.3
     , mtl
     , pretty
     , scientific
-    , template-haskell
-    , temporary
     , text
     , transformers
     , unordered-containers
     , vector
     , yaml >=0.10.0
-  build-tool-depends:
-      hspec-discover:hspec-discover
+  default-language: Haskell2010
+  if impl(ghc >= 9.4.5) && os(windows)
+    build-depends:
+        network >=3.1.2.9
+
+test-suite spec
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
   other-modules:
       Data.Aeson.Config.FromValueSpec
       Data.Aeson.Config.TypesSpec
@@ -190,6 +152,7 @@
       Hpack.Utf8Spec
       Hpack.UtilSpec
       HpackSpec
+      SpecHook
       Data.Aeson.Config.FromValue
       Data.Aeson.Config.Key
       Data.Aeson.Config.KeyMap
@@ -222,6 +185,45 @@
       Paths_hpack
   autogen-modules:
       Paths_hpack
+  hs-source-dirs:
+      test
+      src
+  ghc-options: -Wall -fno-warn-incomplete-uni-patterns
+  cpp-options: -DTEST
+  build-tool-depends:
+      hspec-discover:hspec-discover
+  build-depends:
+      Cabal >=3.0.0.0 && <3.15
+    , Glob >=0.9.0
+    , HUnit >=1.6.0.0
+    , QuickCheck
+    , aeson >=1.4.3.0
+    , base >=4.13 && <5
+    , bifunctors
+    , bytestring
+    , containers
+    , crypton
+    , deepseq
+    , directory >=1.2.5.0
+    , filepath
+    , hspec ==2.*
+    , http-client
+    , http-client-tls >=0.3.6.2
+    , http-types
+    , infer-license >=0.2.0 && <0.3
+    , interpolate
+    , mockery >=0.3
+    , mtl
+    , pretty
+    , scientific
+    , template-haskell
+    , temporary
+    , text
+    , transformers
+    , unordered-containers
+    , vcr
+    , vector
+    , yaml >=0.10.0
   default-language: Haskell2010
   if impl(ghc >= 9.4.5) && os(windows)
     build-depends:
diff --git a/src/Hpack/Config.hs b/src/Hpack/Config.hs
--- a/src/Hpack/Config.hs
+++ b/src/Hpack/Config.hs
@@ -160,6 +160,7 @@
   , packageFlags = []
   , packageExtraSourceFiles = []
   , packageExtraDocFiles = []
+  , packageExtraFiles = []
   , packageDataFiles = []
   , packageDataDir = Nothing
   , packageSourceRepository = Nothing
@@ -602,6 +603,7 @@
 , packageConfigFlags :: Maybe (Map String FlagSection)
 , packageConfigExtraSourceFiles :: Maybe (List FilePath)
 , packageConfigExtraDocFiles :: Maybe (List FilePath)
+, packageConfigExtraFiles :: Maybe (List FilePath)
 , packageConfigDataFiles :: Maybe (List FilePath)
 , packageConfigDataDir :: Maybe FilePath
 , packageConfigGithub :: Maybe GitHub
@@ -831,6 +833,7 @@
         makeVersion [2,2] <$ guard mustSPDX
       , makeVersion [1,24] <$ packageCustomSetup
       , makeVersion [1,18] <$ guard (not (null packageExtraDocFiles))
+      , makeVersion [3,14] <$ guard (not (null packageExtraFiles))
       , packageLibrary >>= libraryCabalVersion
       , internalLibsCabalVersion packageInternalLibraries
       , executablesCabalVersion packageExecutables
@@ -1024,6 +1027,7 @@
 , packageFlags :: [Flag]
 , packageExtraSourceFiles :: [Path]
 , packageExtraDocFiles :: [Path]
+, packageExtraFiles :: [Path]
 , packageDataFiles :: [Path]
 , packageDataDir :: Maybe FilePath
 , packageSourceRepository :: Maybe SourceRepository
@@ -1272,6 +1276,7 @@
 
   extraSourceFiles <- expandGlobs "extra-source-files" dir (fromMaybeList packageConfigExtraSourceFiles)
   extraDocFiles <- expandGlobs "extra-doc-files" dir (fromMaybeList packageConfigExtraDocFiles)
+  extraFiles <- expandGlobs "extra-files" dir (fromMaybeList packageConfigExtraFiles)
 
   let dataBaseDir = maybe dir (dir </>) packageConfigDataDir
 
@@ -1316,6 +1321,7 @@
       , packageFlags = flags
       , packageExtraSourceFiles = extraSourceFiles
       , packageExtraDocFiles = extraDocFiles
+      , packageExtraFiles = extraFiles
       , packageDataFiles = dataFiles
       , packageDataDir = packageConfigDataDir
       , packageSourceRepository = sourceRepository
diff --git a/src/Hpack/Render.hs b/src/Hpack/Render.hs
--- a/src/Hpack/Render.hs
+++ b/src/Hpack/Render.hs
@@ -84,6 +84,7 @@
         Field "tested-with" $ CommaSeparatedList packageTestedWith
       , Field "extra-source-files" (renderPaths packageExtraSourceFiles)
       , Field "extra-doc-files" (renderPaths packageExtraDocFiles)
+      , Field "extra-files" (renderPaths packageExtraFiles)
       , Field "data-files" (renderPaths packageDataFiles)
       ] ++ maybe [] (return . Field "data-dir" . Literal) packageDataDir
 
@@ -116,7 +117,7 @@
         ("name", Just packageName)
       , ("version", Just packageVersion)
       , ("synopsis", packageSynopsis)
-      , ("description", (formatDescription headerFieldsAlignment <$> packageDescription))
+      , ("description", (formatDescription packageCabalVersion headerFieldsAlignment <$> packageDescription))
       , ("category", packageCategory)
       , ("stability", packageStability)
       , ("homepage", packageHomepage)
@@ -144,18 +145,31 @@
       Stanza name fields : xs | Just fieldOrder <- lookup name sectionsFieldOrder -> Stanza name (sortFieldsBy fieldOrder fields) : go xs
       x : xs -> x : go xs
 
-formatDescription :: Alignment -> String -> String
-formatDescription (Alignment alignment) description = case map emptyLineToDot $ lines description of
-  x : xs -> intercalate "\n" (x : map (indentation ++) xs)
+formatDescription :: CabalVersion -> Alignment -> String -> String
+formatDescription cabalVersion (Alignment alignment) description = case map emptyLineToDot $ lines description of
+  x : xs -> intercalate "\n" (x : indent xs)
   [] -> ""
   where
+    n :: Int
     n = max alignment (length ("description: " :: String))
+
+    indentation :: String
     indentation = replicate n ' '
 
+    emptyLineToDot :: String -> String
     emptyLineToDot xs
-      | isEmptyLine xs = "."
+      | isEmptyLine xs && cabalVersion < makeCabalVersion [3] = "."
       | otherwise = xs
 
+    indent :: [String] -> [String]
+    indent = map indentLine
+
+    indentLine :: String -> String
+    indentLine xs
+      | isEmptyLine xs = ""
+      | otherwise = indentation ++ xs
+
+    isEmptyLine :: String -> Bool
     isEmptyLine = all isSpace
 
 renderSourceRepository :: SourceRepository -> Element
diff --git a/test/EndToEndSpec.hs b/test/EndToEndSpec.hs
--- a/test/EndToEndSpec.hs
+++ b/test/EndToEndSpec.hs
@@ -67,6 +67,42 @@
           , GHC == 7.4.2
         |]
 
+    describe "description" $ do
+      it "renders empty lines as dots" $ do
+        [i|
+        description: |
+          foo
+
+          bar
+
+          baz
+        |] `shouldRenderTo` package [i|
+        description: foo
+                     .
+                     bar
+                     .
+                     baz
+        |]
+
+      context "when cabal-version is >= 3" $ do
+        it "preserves empty lines" $ do
+          [i|
+          verbatim:
+            cabal-version: 3.0
+          description: |
+            foo
+
+            bar
+
+            baz
+          |] `shouldRenderTo` (package [i|
+          description: foo
+
+                       bar
+
+                       baz
+          |]) { packageCabalVersion = "3.0" }
+
     describe "handling of Paths_ module" $ do
       it "adds Paths_ to other-modules" $ do
         [i|
@@ -424,7 +460,6 @@
         |] `shouldFailWith` [i|cycle in defaults (#{canonic1} -> #{canonic2} -> #{canonic1})|]
 
       it "fails if defaults don't exist" $ do
-        pending
         [i|
         defaults:
           github: sol/foo
@@ -637,6 +672,20 @@
         extra-doc-files:
           - "*.markdown"
         |] `shouldWarn` ["Specified pattern \"*.markdown\" for extra-doc-files does not match any files"]
+
+    describe "extra-files" $ do
+      it "accepts extra-files" $ do
+        touch "CHANGES.markdown"
+        touch "README.markdown"
+        [i|
+        extra-files:
+          - CHANGES.markdown
+          - README.markdown
+        |] `shouldRenderTo` (package [i|
+        extra-files:
+            CHANGES.markdown
+            README.markdown
+        |]) {packageCabalVersion = "3.14"}
 
     describe "build-tools" $ do
       context "with known build tools" $ do
diff --git a/test/Hpack/DefaultsSpec.hs b/test/Hpack/DefaultsSpec.hs
--- a/test/Hpack/DefaultsSpec.hs
+++ b/test/Hpack/DefaultsSpec.hs
@@ -22,7 +22,6 @@
       url = "https://raw.githubusercontent.com/sol/hpack/master/Setup.lhs"
 
     it "downloads file if missing" $ do
-      pending
       expected <- readFile "Setup.lhs"
       inTempDirectory $ do
         Found <- ensureFile file url
@@ -41,7 +40,6 @@
         url = "https://raw.githubusercontent.com/sol/hpack/master/Setup.foo"
 
       it "does not create any files" $ do
-        pending
         inTempDirectory $ do
           NotFound <- ensureFile file url
           doesFileExist file `shouldReturn` False
diff --git a/test/Hpack/RenderSpec.hs b/test/Hpack/RenderSpec.hs
--- a/test/Hpack/RenderSpec.hs
+++ b/test/Hpack/RenderSpec.hs
@@ -26,6 +26,9 @@
 cabalVersion :: CabalVersion
 cabalVersion = makeCabalVersion [1,12]
 
+cabal30 :: CabalVersion
+cabal30 = makeCabalVersion [3,0,0]
+
 spec :: Spec
 spec = do
   describe "renderPackageWith" $ do
@@ -284,7 +287,7 @@
               "foo"
             , "bar"
             ]
-      "description: " ++ formatDescription 0 description `shouldBe` intercalate "\n" [
+      "description: " ++ formatDescription cabalVersion 0 description `shouldBe` intercalate "\n" [
           "description: foo"
         , "             bar"
         ]
@@ -295,7 +298,7 @@
             , "bar"
             , "baz"
             ]
-      "description:   " ++ formatDescription 15 description `shouldBe` intercalate "\n" [
+      "description:   " ++ formatDescription cabalVersion 15 description `shouldBe` intercalate "\n" [
           "description:   foo"
         , "               bar"
         , "               baz"
@@ -307,11 +310,36 @@
             , "   "
             , "bar"
             ]
-      "description: " ++ formatDescription 0 description `shouldBe` intercalate "\n" [
+      "description: " ++ formatDescription cabalVersion 0 description `shouldBe` intercalate "\n" [
           "description: foo"
         , "             ."
         , "             bar"
         ]
+
+    it "correctly handles empty lines at the beginning" $ do
+      let description = unlines [
+              ""
+            , "foo"
+            , "bar"
+            ]
+      "description: " ++ formatDescription cabalVersion 0 description `shouldBe` intercalate "\n" [
+          "description: ."
+        , "             foo"
+        , "             bar"
+        ]
+
+    context "when cabal-version is >= 3" $ do
+      it "preserves empty lines" $ do
+        let description = unlines [
+                "foo"
+              , ""
+              , "bar"
+              ]
+        "description: " ++ formatDescription cabal30 0 description `shouldBe` intercalate "\n" [
+            "description: foo"
+          , ""
+          , "             bar"
+          ]
 
   describe "renderSourceRepository" $ do
     it "renders source-repository without subdir correctly" $ do
diff --git a/test/SpecHook.hs b/test/SpecHook.hs
new file mode 100644
--- /dev/null
+++ b/test/SpecHook.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE OverloadedStrings #-}
+module SpecHook where
+
+import           Test.Hspec
+import qualified VCR
+
+hook :: Spec -> Spec
+hook = aroundAll_ (VCR.with "test/fixtures/vcr-tape.yaml")
